]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Signal handler ucontext_t not filled out correctly on OS X
authorRhys Kidd <rhyskidd@gmail.com>
Thu, 28 May 2015 12:49:00 +0000 (12:49 +0000)
committerRhys Kidd <rhyskidd@gmail.com>
Thu, 28 May 2015 12:49:00 +0000 (12:49 +0000)
bz#341419

Before:

== 589 tests, 220 stderr failures, 15 stdout failures, 0 stderrB failures, 0 stdoutB failures, 30 post failures ==

After:

== 591 tests, 220 stderr failures, 15 stdout failures, 0 stderrB failures, 0 stdoutB failures, 30 post failures ==

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15296

18 files changed:
NEWS
auxprogs/valgrind-di-server.c
configure.ac
coregrind/m_sigframe/sigframe-amd64-darwin.c
coregrind/m_sigframe/sigframe-x86-darwin.c
include/vki/vki-darwin.h
none/tests/Makefile.am
none/tests/amd64-darwin/Makefile.am [new file with mode: 0644]
none/tests/amd64-darwin/bug341419.c [new file with mode: 0644]
none/tests/amd64-darwin/bug341419.stderr.exp [new file with mode: 0644]
none/tests/amd64-darwin/bug341419.vgtest [new file with mode: 0644]
none/tests/amd64-darwin/filter_minimal [new file with mode: 0755]
none/tests/amd64-darwin/filter_stderr [new file with mode: 0755]
none/tests/x86-darwin/Makefile.am [new file with mode: 0644]
none/tests/x86-darwin/bug341419.c [new file with mode: 0644]
none/tests/x86-darwin/bug341419.stderr.exp [new file with mode: 0644]
none/tests/x86-darwin/bug341419.vgtest [new file with mode: 0644]
none/tests/x86-darwin/filter_stderr [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index d482bf980a0554a35408ad28e4f7d0386d23d60f..357adb972d61ccf5acf7af3752238faf6ea5b099 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -139,6 +139,7 @@ where XXXXXX is the bug number as listed below.
 340115  Fix none/tests/cmdline[1|2] tests on systems which define TMPDIR
 340430  Fix some grammatical weirdness in the manual.
 341238  Recognize GCC5/DWARFv5 DW_LANG constants (Go, C11, C++11, C++14)
+341419  Signal handler ucontext_t not filled out correctly on OS X
 341539  VG_(describe_addr) should not describe address as belonging to client
         segment if it is past the heap end
 341613  Enable building of manythreads and thread-exits tests on Mac OS X
index bfcdd1875e5583c162620904ff8ab8a54449b58f..86c588280c648eeb1183c6a8d89bf81329d9ec4e 100644 (file)
@@ -89,7 +89,9 @@
 #include "pub_core_libcfile.h"      // For VG_CLO_DEFAULT_LOGPORT
 
 /* Needed to get a definition for pread() from unistd.h */
+#ifndef _XOPEN_SOURCE
 #define _XOPEN_SOURCE 500
+#endif
 
 #include <stdio.h>
 #include <unistd.h>
index 7faeac2991b801fa7641f163abdb09a117639cf6..eac62cd19dc3303c33c64d9ce72ca710b144bfec 100644 (file)
@@ -3037,6 +3037,8 @@ AC_CONFIG_FILES([
    none/tests/darwin/Makefile
    none/tests/amd64-linux/Makefile
    none/tests/x86-linux/Makefile
+   none/tests/amd64-darwin/Makefile
+   none/tests/x86-darwin/Makefile
    exp-sgcheck/Makefile
    exp-sgcheck/tests/Makefile
    drd/Makefile
index 20402bfcfec1dca438b685e9423762639b3c602a..1d284bea34ad6b6119e08ea002b3b12a074df7eb 100644 (file)
 #include "pub_core_tooliface.h"
 #include "pub_core_trampoline.h"
 #include "pub_core_sigframe.h"      /* self */
+#include "priv_sigframe.h"
 
 
-/* Cheap-ass hack copied from ppc32-aix5 code, just to get started.
-   Produce a frame with layout entirely of our own choosing. */
+/* Originally copied from ppc32-aix5 code.
+   Produce a frame with layout entirely of our own choosing.
 
-/* This module creates and removes signal frames for signal deliveries
-   on amd64-darwin.  Kludgey; the machine state ought to be saved in a
-   ucontext and retrieved from it later, so the handler can modify it
-   and return.  However .. for now .. just stick the vex guest state
-   in the frame and snarf it again later.
-
-   Also, don't bother with creating siginfo and ucontext in the
-   handler, although do point them somewhere non-faulting.
+   This module creates and removes signal frames for signal deliveries
+   on amd64-darwin.  The machine state is saved in a ucontext and retrieved
+   from it later, so the handler can modify it and return.
 
    Frame should have a 16-aligned size, just in case that turns out to
    be important for Darwin.  (be conservative)
@@ -66,20 +62,82 @@ struct hacky_sigframe {
    /* first word looks like a call to a 3-arg amd64-ELF function */
    ULong               returnAddr;
    UChar               lower_guardzone[512];  // put nothing here
-   VexGuestAMD64State  gst;
-   VexGuestAMD64State  gshadow1;
-   VexGuestAMD64State  gshadow2;
+   VexGuestAMD64State  vex;
+   VexGuestAMD64State  vex_shadow1;
+   VexGuestAMD64State  vex_shadow2;
    vki_siginfo_t       fake_siginfo;
    struct vki_ucontext fake_ucontext;
    UInt                magicPI;
    UInt                sigNo_private;
    vki_sigset_t        mask; // saved sigmask; restore when hdlr returns
-   UInt                __pad[2];
    UChar               upper_guardzone[512]; // put nothing here
    // and don't zero it, since that might overwrite the client's
    // stack redzone, at least on archs which have one
 };
 
+/* Create a plausible-looking sigcontext from the thread's
+   Vex guest state.  NOTE: does not fill in the FP or SSE
+   bits of sigcontext at the moment.
+ */
+static void synthesize_ucontext(ThreadState *tst,
+                               struct vki_ucontext *uc,
+                               const struct vki_ucontext *siguc)
+{
+   VG_(memset)(uc, 0, sizeof(*uc));
+
+   if (siguc) uc->uc_sigmask = siguc->uc_sigmask;
+   uc->uc_stack = tst->altstack;
+   uc->uc_mcontext = &uc->__mcontext_data;
+
+#  define SC2(reg,REG)  uc->__mcontext_data.__ss.reg = tst->arch.vex.guest_##REG
+   SC2(__r8,R8);
+   SC2(__r9,R9);
+   SC2(__r10,R10);
+   SC2(__r11,R11);
+   SC2(__r12,R12);
+   SC2(__r13,R13);
+   SC2(__r14,R14);
+   SC2(__r15,R15);
+   SC2(__rdi,RDI);
+   SC2(__rsi,RSI);
+   SC2(__rbp,RBP);
+   SC2(__rbx,RBX);
+   SC2(__rdx,RDX);
+   SC2(__rax,RAX);
+   SC2(__rcx,RCX);
+   SC2(__rsp,RSP);
+   SC2(__rip,RIP);
+   uc->__mcontext_data.__ss.__rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex);
+
+   if (siguc)
+      uc->__mcontext_data.__es = siguc->__mcontext_data.__es;
+#  undef SC2
+}
+
+static void restore_from_ucontext(ThreadState *tst,
+                                 const struct vki_ucontext *uc)
+{
+#  define SC2(REG,reg)  tst->arch.vex.guest_##REG = uc->__mcontext_data.__ss.reg
+   SC2(R8,__r8);
+   SC2(R9,__r9);
+   SC2(R10,__r10);
+   SC2(R11,__r11);
+   SC2(R12,__r12);
+   SC2(R13,__r13);
+   SC2(R14,__r14);
+   SC2(R15,__r15);
+   SC2(RDI,__rdi);
+   SC2(RSI,__rsi);
+   SC2(RBP,__rbp);
+   SC2(RBX,__rbx);
+   SC2(RDX,__rdx);
+   SC2(RAX,__rax);
+   SC2(RCX,__rcx);
+   SC2(RSP,__rsp);
+   SC2(RIP,__rip);
+   /* There doesn't seem to be an easy way to restore rflags */
+#  undef SC2
+}
 
 /* Create a signal frame for thread 'tid'.  Make a 3-arg frame
    regardless of whether the client originally requested a 1-arg
@@ -115,26 +173,25 @@ void VG_(sigframe_create) ( ThreadId tid,
 
    frame = (struct hacky_sigframe *) rsp;
 
-   /* clear it (very conservatively) (why so conservatively??) */
+   /* clear it (very conservatively) */
    VG_(memset)(&frame->lower_guardzone, 0, sizeof frame->lower_guardzone);
-   VG_(memset)(&frame->gst,      0, sizeof(VexGuestAMD64State));
-   VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestAMD64State));
-   VG_(memset)(&frame->gshadow2, 0, sizeof(VexGuestAMD64State));
+   VG_(memset)(&frame->vex,      0, sizeof(VexGuestAMD64State));
+   VG_(memset)(&frame->vex_shadow1, 0, sizeof(VexGuestAMD64State));
+   VG_(memset)(&frame->vex_shadow2, 0, sizeof(VexGuestAMD64State));
    VG_(memset)(&frame->fake_siginfo,  0, sizeof(frame->fake_siginfo));
    VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext));
 
    /* save stuff in frame */
-   frame->gst           = tst->arch.vex;
-   frame->gshadow1      = tst->arch.vex_shadow1;
-   frame->gshadow2      = tst->arch.vex_shadow2;
+   frame->vex           = tst->arch.vex;
+   frame->vex_shadow1   = tst->arch.vex_shadow1;
+   frame->vex_shadow2   = tst->arch.vex_shadow2;
    frame->sigNo_private = sigNo;
    frame->mask          = tst->sig_mask;
    frame->magicPI       = 0x31415927;
 
-   /* Minimally fill in the siginfo and ucontext.  Note, utter
-      lameness prevails.  Be underwhelmed, be very underwhelmed. */
-   frame->fake_siginfo.si_signo = sigNo;
-   frame->fake_siginfo.si_code  = siginfo->si_code;
+   /* Fill in the siginfo and ucontext.  */
+   synthesize_ucontext(tst, &frame->fake_ucontext, siguc);
+   frame->fake_siginfo = *siginfo;
 
    /* Set up stack pointer */
    vg_assert(rsp == (Addr)&frame->returnAddr);
@@ -152,8 +209,8 @@ void VG_(sigframe_create) ( ThreadId tid,
 
    /* XXX should tell the tool that these regs got written */
    tst->arch.vex.guest_RDI = (ULong) sigNo;
-   tst->arch.vex.guest_RSI = (Addr)  &frame->fake_siginfo;/* oh well */
-   tst->arch.vex.guest_RDX = (Addr)  &frame->fake_ucontext; /* oh well */
+   tst->arch.vex.guest_RSI = (Addr)  &frame->fake_siginfo;
+   tst->arch.vex.guest_RDX = (Addr)  &frame->fake_ucontext;
 
    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
              (Addr)frame, 1*sizeof(ULong) );
@@ -198,9 +255,11 @@ void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
    /* restore the entire guest state, and shadows, from the
       frame.  Note, as per comments above, this is a kludge - should
       restore it from saved ucontext.  Oh well. */
-   tst->arch.vex = frame->gst;
-   tst->arch.vex_shadow1 = frame->gshadow1;
-   tst->arch.vex_shadow2 = frame->gshadow2;
+   tst->arch.vex = frame->vex;
+   tst->arch.vex_shadow1 = frame->vex_shadow1;
+   tst->arch.vex_shadow2 = frame->vex_shadow2;
+   restore_from_ucontext(tst, &frame->fake_ucontext);
+
    tst->sig_mask = frame->mask;
    tst->tmp_sig_mask = frame->mask;
    sigNo = frame->sigNo_private;
index 01f87da0202f7a509ae247bcca01ddbc4b658dc8..769fdbdc2c1f6c63221a1cf51a9e143b25e765e9 100644 (file)
 #include "pub_core_tooliface.h"
 #include "pub_core_trampoline.h"
 #include "pub_core_sigframe.h"      /* self */
+#include "priv_sigframe.h"
 
 
-/* Cheap-ass hack copied from ppc32-aix5 code, just to get started.
-   Produce a frame with layout entirely of our own choosing. */
+/* Originally copied from ppc32-aix5 code.
+   Produce a frame with layout entirely of our own choosing.
 
-/* This module creates and removes signal frames for signal deliveries
-   on x86-darwin.  Kludgey; the machine state ought to be saved in a
-   ucontext and retrieved from it later, so the handler can modify it
-   and return.  However .. for now .. just stick the vex guest state
-   in the frame and snarf it again later.
-
-   Also, don't bother with creating siginfo and ucontext in the
-   handler, although do point them somewhere non-faulting.
+   This module creates and removes signal frames for signal deliveries
+   on x86-darwin.  The machine state is saved in a ucontext and retrieved
+   from it later, so the handler can modify it and return.
 
    Frame should have a 16-aligned size, just in case that turns out to
    be important for Darwin.  (be conservative)
@@ -77,12 +73,59 @@ struct hacky_sigframe {
    UInt             magicPI;
    UInt             sigNo_private;
    vki_sigset_t     mask; // saved sigmask; restore when hdlr returns
-   UInt             __pad[1];
+   UInt             __pad[3];
    UChar            upper_guardzone[512]; // put nothing here
    // and don't zero it, since that might overwrite the client's
    // stack redzone, at least on archs which have one
 };
 
+/* Create a plausible-looking sigcontext from the thread's
+   Vex guest state.  NOTE: does not fill in the FP or SSE
+   bits of sigcontext at the moment.
+ */
+static void synthesize_ucontext(ThreadState *tst,
+                               struct vki_ucontext *uc,
+                               const struct vki_ucontext *siguc)
+{
+   VG_(memset)(uc, 0, sizeof(*uc));
+
+   if (siguc) uc->uc_sigmask = siguc->uc_sigmask;
+   uc->uc_stack = tst->altstack;
+   uc->uc_mcontext = &uc->__mcontext_data;
+
+#  define SC2(reg,REG)  uc->__mcontext_data.__ss.reg = tst->arch.vex.guest_##REG
+   SC2(__edi,EDI);
+   SC2(__esi,ESI);
+   SC2(__ebp,EBP);
+   SC2(__ebx,EBX);
+   SC2(__edx,EDX);
+   SC2(__eax,EAX);
+   SC2(__ecx,ECX);
+   SC2(__esp,ESP);
+   SC2(__eip,EIP);
+   uc->__mcontext_data.__ss.__eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
+
+   if (siguc)
+      uc->__mcontext_data.__es = siguc->__mcontext_data.__es;
+#  undef SC2
+}
+
+static void restore_from_ucontext(ThreadState *tst,
+                                 const struct vki_ucontext *uc)
+{
+#  define SC2(REG,reg)  tst->arch.vex.guest_##REG = uc->__mcontext_data.__ss.reg
+   SC2(EDI,__edi);
+   SC2(ESI,__esi);
+   SC2(EBP,__ebp);
+   SC2(EBX,__ebx);
+   SC2(EDX,__edx);
+   SC2(EAX,__eax);
+   SC2(ECX,__ecx);
+   SC2(ESP,__esp);
+   SC2(EIP,__eip);
+   /* There doesn't seem to be an easy way to restore eflags */
+#  undef SC2
+}
 
 /* Create a signal frame for thread 'tid'.  Make a 3-arg frame
    regardless of whether the client originally requested a 1-arg
@@ -118,7 +161,7 @@ void VG_(sigframe_create) ( ThreadId tid,
 
    frame = (struct hacky_sigframe *) esp;
 
-   /* clear it (very conservatively) (why so conservatively??) */
+   /* clear it (very conservatively) */
    VG_(memset)(&frame->lower_guardzone, 0, sizeof frame->lower_guardzone);
    VG_(memset)(&frame->gst,      0, sizeof(VexGuestX86State));
    VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestX86State));
@@ -134,10 +177,9 @@ void VG_(sigframe_create) ( ThreadId tid,
    frame->mask          = tst->sig_mask;
    frame->magicPI       = 0x31415927;
 
-   /* Minimally fill in the siginfo and ucontext.  Note, utter
-      lameness prevails.  Be underwhelmed, be very underwhelmed. */
-   frame->fake_siginfo.si_signo = sigNo;
-   frame->fake_siginfo.si_code  = siginfo->si_code;
+   /* Fill in the siginfo and ucontext.  */
+   synthesize_ucontext(tst, &frame->fake_ucontext, siguc);
+   frame->fake_siginfo = *siginfo;
 
    /* Set up stack pointer */
    vg_assert(esp == (Addr)&frame->returnAddr);
@@ -153,8 +195,8 @@ void VG_(sigframe_create) ( ThreadId tid,
              (Addr)frame, 4*sizeof(UInt) );
    frame->returnAddr  = (UInt)&VG_(x86_darwin_SUBST_FOR_sigreturn);
    frame->a1_signo    = sigNo;
-   frame->a2_siginfo  = (UInt)&frame->fake_siginfo;  /* oh well */
-   frame->a3_ucontext = (UInt)&frame->fake_ucontext; /* oh well */
+   frame->a2_siginfo  = (UInt)&frame->fake_siginfo;
+   frame->a3_ucontext = (UInt)&frame->fake_ucontext;
    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
              (Addr)frame, 4*sizeof(UInt) );
    VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
@@ -201,6 +243,8 @@ void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
    tst->arch.vex = frame->gst;
    tst->arch.vex_shadow1 = frame->gshadow1;
    tst->arch.vex_shadow2 = frame->gshadow2;
+   restore_from_ucontext(tst, &frame->fake_ucontext);
+
    tst->sig_mask = frame->mask;
    tst->tmp_sig_mask = frame->mask;
    sigNo = frame->sigNo_private;
index 9e53f25bfa0f1769b2b626c953975e9b3fd3e5d0..7ff7c5bc0aacc734f146eba35768011ec5ff7a0e 100644 (file)
 #ifndef __VKI_DARWIN_H
 #define __VKI_DARWIN_H
 
+/* struct __darwin_ucontext isn't fully declared without
+ * this definition.  It's crazy but there it is.  */
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 0500
+#endif
+
 #include <stdint.h>
 
 #define vki_int8_t int8_t
index 1dfcfc498dc6f2b3674c51c8113bafe7e4d5994a..c9c9c81d8c39c33ce400cbbb4e34f7762ab1e544 100644 (file)
@@ -52,8 +52,16 @@ if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
 SUBDIRS += x86-linux
 endif
 
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+SUBDIRS += amd64-darwin
+endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+SUBDIRS += x86-darwin
+endif
+
 DIST_SUBDIRS = x86 amd64 ppc32 ppc64 arm arm64 s390x mips32 mips64 tilegx \
-               linux darwin amd64-linux x86-linux scripts .
+              linux darwin amd64-linux x86-linux amd64-darwin \
+              x86-darwin scripts .
 
 dist_noinst_SCRIPTS = \
        filter_cmdline0 \
diff --git a/none/tests/amd64-darwin/Makefile.am b/none/tests/amd64-darwin/Makefile.am
new file mode 100644 (file)
index 0000000..b231b30
--- /dev/null
@@ -0,0 +1,15 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = \
+       filter_stderr filter_minimal
+
+EXTRA_DIST = \
+       bug341419.vgtest bug341419.stderr.exp
+
+check_PROGRAMS = \
+       bug341419
+
+AM_CFLAGS    += @FLAG_M64@
+AM_CXXFLAGS  += @FLAG_M64@
+AM_CCASFLAGS += @FLAG_M64@
diff --git a/none/tests/amd64-darwin/bug341419.c b/none/tests/amd64-darwin/bug341419.c
new file mode 100644 (file)
index 0000000..e4fdacd
--- /dev/null
@@ -0,0 +1,223 @@
+/* This changes the definition of ucontext_t */
+#define _XOPEN_SOURCE 1
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdbool.h>
+#include <valgrind.h>
+
+#define offsetof(type, fld)    ((unsigned long)&((type *)0)->fld)
+#define stringify(x)           #x
+
+static int verbose = 0;
+
+#define _ASSERT_OP(a, op, b) \
+    do { \
+       unsigned long long _a = (unsigned long long)(a); \
+       unsigned long long _b = (unsigned long long)(b); \
+       if (verbose) \
+           fprintf(stderr, "%s:%d: ASSERT(" stringify(a) \
+                   " " stringify(op) " " stringify(b) ")\n", \
+                   __FILE__, __LINE__); \
+       if (!(_a op _b)) { \
+           fprintf(stderr, "%s:%d: FAILED ASSERT((" stringify(a) \
+                   "=0x%016llx) " stringify(op) " (" stringify(b) "=0x%016llx))\n", \
+                   __FILE__, __LINE__, _a, _b); \
+           _exit(1); \
+       } \
+    } while(0)
+#define ASSERT_EQ(a, b) _ASSERT_OP(a, ==, b)
+#define ASSERT_NE(a, b) _ASSERT_OP(a, !=, b)
+#define ASSERT_LTE(a, b) _ASSERT_OP(a, <=, b)
+#define ASSERT_GTE(a, b) _ASSERT_OP(a, >=, b)
+#define ASSERT(e) \
+    do { \
+       if (verbose) \
+           fprintf(stderr, "%s:%d: ASSERT(" stringify(e) ")\n", \
+                   __FILE__, __LINE__); \
+       if (!(e)) { \
+           fprintf(stderr, "%s:%d: FAILED ASSERT(" stringify(e) ")\n", \
+                   __FILE__, __LINE__); \
+           _exit(1); \
+       } \
+    } while(0)
+
+
+static bool using_int3 = false;
+static volatile int sig_count = 0;
+static volatile int ran_after_fault = 0;
+static void *top_of_stack;
+static void *bottom_of_stack;
+
+void this_function_halts(unsigned long long a0, unsigned long long a1,
+                        unsigned long long a2, unsigned long long a3,
+                        unsigned long long a4, unsigned long long a5)
+{
+    int foo;
+    bottom_of_stack = &foo;
+
+    /* Set up registers with known values which will be tested in the signal handler */
+    __asm__ volatile("movq $0xfeed01010101cafe,%rax");
+    __asm__ volatile("movq $0xfeed02020202cafe,%rbx");
+    __asm__ volatile("movq $0xfeed03030303cafe,%r10");
+    __asm__ volatile("movq $0xfeed04040404cafe,%r11");
+    __asm__ volatile("movq $0xfeed05050505cafe,%r12");
+    __asm__ volatile("movq $0xfeed06060606cafe,%r13");
+    __asm__ volatile("movq $0xfeed07070707cafe,%r14");
+    __asm__ volatile("movq $0xfeed08080808cafe,%r15");
+    __asm__ volatile("hlt");
+    ran_after_fault++;
+}
+
+void this_function_int3s(unsigned long long a0, unsigned long long a1,
+                        unsigned long long a2, unsigned long long a3,
+                        unsigned long long a4, unsigned long long a5)
+{
+    int foo;
+    bottom_of_stack = &foo;
+
+    /* Set up registers with known values which will be tested in the signal handler */
+    __asm__ volatile("movq $0xfeed01010101cafe,%rax");
+    __asm__ volatile("movq $0xfeed02020202cafe,%rbx");
+    __asm__ volatile("movq $0xfeed03030303cafe,%r10");
+    __asm__ volatile("movq $0xfeed04040404cafe,%r11");
+    __asm__ volatile("movq $0xfeed05050505cafe,%r12");
+    __asm__ volatile("movq $0xfeed06060606cafe,%r13");
+    __asm__ volatile("movq $0xfeed07070707cafe,%r14");
+    __asm__ volatile("movq $0xfeed08080808cafe,%r15");
+    __asm__ volatile("int $3");
+    ran_after_fault++;
+}
+
+
+static void
+handle_signal(int sig, siginfo_t *si, void *vuc)
+{
+    ucontext_t *uc = (ucontext_t *)vuc;
+
+    if (verbose)
+    {
+       fprintf(stderr, "handle_signal\n");
+       fflush(stderr);
+    }
+
+    sig_count++;
+    ASSERT(sig_count == 1);
+
+    int expected_sig = (using_int3 ? SIGTRAP : SIGSEGV);
+    ASSERT_EQ(sig, expected_sig);
+    ASSERT_NE(si, NULL);
+    ASSERT_NE(uc, NULL);
+    ASSERT_NE(uc->uc_mcontext, NULL);
+
+    /* Test that the siginfo is set up right for this signal */
+    ASSERT_EQ(si->si_signo, expected_sig);
+    ASSERT_EQ(si->si_errno, 0);
+    int expected_code = (using_int3 ? 1 : 0);
+    ASSERT_EQ(si->si_code, expected_code);
+    ASSERT_EQ(si->si_pid, 0);
+    ASSERT_EQ(si->si_uid, 0);
+    ASSERT_EQ(si->si_status, 0);
+    ASSERT_EQ(si->si_addr, 0);
+    ASSERT_EQ(si->si_band, 0);
+
+    /* Test that RAX is saved to the signal ucontext */
+    ASSERT_EQ(uc->uc_mcontext->__ss.__rax, 0xfeed01010101cafe);
+
+    /* Test that the registers used to pass the 1st 6
+     * function arguments were saved in the signal ucontext */
+    ASSERT_EQ(uc->uc_mcontext->__ss.__rdi, 0xbabe01010101cedeULL);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__rsi, 0xbabe02020202cedeULL);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__rdx, 0xbabe03030303cedeULL);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__rcx, 0xbabe04040404cedeULL);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__r8, 0xbabe05050505cedeULL);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__r9, 0xbabe06060606cedeULL);
+
+    /* Test that the saved RBP and RSP point into roughly the right
+     * part of the stack */
+    ASSERT_GTE(uc->uc_mcontext->__ss.__rbp, bottom_of_stack);
+    ASSERT_LTE(uc->uc_mcontext->__ss.__rbp, top_of_stack);
+    ASSERT_GTE(uc->uc_mcontext->__ss.__rsp, bottom_of_stack);
+    ASSERT_LTE(uc->uc_mcontext->__ss.__rsp, top_of_stack);
+
+    /* Test that the saved RIP points into roughly the
+     * right part of the text segment */
+    char *calling_fn = (using_int3 ? (char *)&this_function_int3s : (char *)&this_function_halts);
+    ASSERT_GTE(uc->uc_mcontext->__ss.__rip, calling_fn);
+    ASSERT_LTE(uc->uc_mcontext->__ss.__rip, calling_fn+400);
+
+    ASSERT_EQ(uc->uc_mcontext->__ss.__rbx, 0xfeed02020202cafe);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__r10, 0xfeed03030303cafe);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__r11, 0xfeed04040404cafe);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__r12, 0xfeed05050505cafe);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__r13, 0xfeed06060606cafe);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__r14, 0xfeed07070707cafe);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__r15, 0xfeed08080808cafe);
+    /*
+    printf("       RFLAGS 0x%016llx\n", (unsigned long long)uc->uc_mcontext->__ss.__rflags);
+    */
+
+    /*
+     * Test that the RIP is restored from the signal ucontext;
+     * this should skip past the HLT/INT instruction and
+     * allow execution to continue back out to main()
+     */
+    if (verbose)
+    {
+       fprintf(stderr, "Setting up to return past the HLT\n");
+       fflush(stderr);
+    }
+    uc->uc_mcontext->__ss.__rip += (using_int3 ? 0 : 1);
+
+    if (verbose)
+    {
+       fprintf(stderr, "Returning from signal handler\n");
+       fflush(stderr);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    int r;
+    struct sigaction act;
+
+    top_of_stack = (void *)&act;
+
+    if (argc > 1 && !strcmp(argv[1], "--verbose"))
+       verbose = 1;
+
+    if (verbose)
+       printf("Setting up signal handler\n");
+    memset(&act, 0, sizeof(act));
+    act.sa_sigaction = handle_signal;
+    act.sa_flags |= SA_SIGINFO;
+    if (RUNNING_ON_VALGRIND)
+       using_int3 = true;
+    r = sigaction((using_int3 ? SIGTRAP : SIGSEGV), &act, NULL);
+    ASSERT_EQ(r, 0);
+
+    if (verbose)
+    {
+       fprintf(stderr, "Calling function with a breakpoint insn in it\n");
+       fflush(stderr);
+    }
+    if (using_int3)
+       this_function_int3s(0xbabe01010101cedeULL,
+                           0xbabe02020202cedeULL,
+                           0xbabe03030303cedeULL,
+                           0xbabe04040404cedeULL,
+                           0xbabe05050505cedeULL,
+                           0xbabe06060606cedeULL);
+    else
+       this_function_halts(0xbabe01010101cedeULL,
+                           0xbabe02020202cedeULL,
+                           0xbabe03030303cedeULL,
+                           0xbabe04040404cedeULL,
+                           0xbabe05050505cedeULL,
+                           0xbabe06060606cedeULL);
+    ASSERT_EQ(ran_after_fault, 1);
+
+    fprintf(stderr, "PASS\n");
+    return 0;
+}
diff --git a/none/tests/amd64-darwin/bug341419.stderr.exp b/none/tests/amd64-darwin/bug341419.stderr.exp
new file mode 100644 (file)
index 0000000..7ef22e9
--- /dev/null
@@ -0,0 +1 @@
+PASS
diff --git a/none/tests/amd64-darwin/bug341419.vgtest b/none/tests/amd64-darwin/bug341419.vgtest
new file mode 100644 (file)
index 0000000..baae689
--- /dev/null
@@ -0,0 +1,3 @@
+prog: bug341419
+vgopts: -q
+cleanup: rm -f vgcore.*
diff --git a/none/tests/amd64-darwin/filter_minimal b/none/tests/amd64-darwin/filter_minimal
new file mode 100755 (executable)
index 0000000..e69398c
--- /dev/null
@@ -0,0 +1,20 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+# Remove ==pid== and **pid** strings 
+perl -p -e 's/(==|\*\*)[0-9]{1,7}\1 //' |
+
+perl -p -e 's/0x[0-9A-Fa-f]+/0x......../g' |
+
+# Older bash versions print abnormal termination messages on the stderr
+# of the bash process. Newer bash versions redirect such messages properly.
+# Suppress any redirected abnormal termination messages. You can find the
+# complete list of messages in the bash source file siglist.c.
+perl -n -e 'print if !/^(Segmentation fault|Alarm clock|Aborted|Bus error)( \(core dumped\))?$/' |
+
+# Remove the size in "The main thread stack size..." message.
+sed "s/The main thread stack size used in this run was [0-9]*/The main thread stack size used in this run was .../"
+
+# NOTE: it is essential for the bug345887 testcase that the stderr
+#       filtering does *not* remove lines beginning with --
diff --git a/none/tests/amd64-darwin/filter_stderr b/none/tests/amd64-darwin/filter_stderr
new file mode 100755 (executable)
index 0000000..587754a
--- /dev/null
@@ -0,0 +1,11 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+# Remove ==pid== and --pid-- and **pid** strings 
+perl -p -e 's/(==|--|\*\*)[0-9]{1,7}\1 //' |
+
+perl -p -e 's/0x[0-9A-Fa-f]+/0x......../g'
+
+# NOTE: it is essential for the bug345887 testcase that the stderr
+#       filtering does *not* remove lines beginning with --
diff --git a/none/tests/x86-darwin/Makefile.am b/none/tests/x86-darwin/Makefile.am
new file mode 100644 (file)
index 0000000..0b76f95
--- /dev/null
@@ -0,0 +1,15 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = \
+       filter_stderr
+
+EXTRA_DIST = \
+       bug341419.vgtest bug341419.stderr.exp
+
+check_PROGRAMS = \
+       bug341419
+
+AM_CFLAGS    += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
+AM_CXXFLAGS  += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
+AM_CCASFLAGS += @FLAG_M32@
diff --git a/none/tests/x86-darwin/bug341419.c b/none/tests/x86-darwin/bug341419.c
new file mode 100644 (file)
index 0000000..ef2d52e
--- /dev/null
@@ -0,0 +1,203 @@
+/* This changes the definition of ucontext_t */
+#define _XOPEN_SOURCE 1
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdbool.h>
+#include <valgrind.h>
+
+#define offsetof(type, fld)    ((unsigned long)&((type *)0)->fld)
+#define stringify(x)           #x
+
+static int verbose = 0;
+
+#define _ASSERT_OP(a, op, b) \
+    do { \
+       unsigned long long _a = (unsigned long long)(a); \
+       unsigned long long _b = (unsigned long long)(b); \
+       if (verbose) \
+           fprintf(stderr, "%s:%d: ASSERT(" stringify(a) \
+                   " " stringify(op) " " stringify(b) ")\n", \
+                   __FILE__, __LINE__); \
+       if (!(_a op _b)) { \
+           fprintf(stderr, "%s:%d: FAILED ASSERT((" stringify(a) \
+                   "=0x%016llx) " stringify(op) " (" stringify(b) "=0x%016llx))\n", \
+                   __FILE__, __LINE__, _a, _b); \
+           _exit(1); \
+       } \
+    } while(0)
+#define ASSERT_EQ(a, b) _ASSERT_OP(a, ==, b)
+#define ASSERT_NE(a, b) _ASSERT_OP(a, !=, b)
+#define ASSERT_LTE(a, b) _ASSERT_OP(a, <=, b)
+#define ASSERT_GTE(a, b) _ASSERT_OP(a, >=, b)
+#define ASSERT(e) \
+    do { \
+       if (verbose) \
+           fprintf(stderr, "%s:%d: ASSERT(" stringify(e) ")\n", \
+                   __FILE__, __LINE__); \
+       if (!(e)) { \
+           fprintf(stderr, "%s:%d: FAILED ASSERT(" stringify(e) ")\n", \
+                   __FILE__, __LINE__); \
+           _exit(1); \
+       } \
+    } while(0)
+
+
+static bool using_int3 = false;
+static volatile int sig_count = 0;
+static volatile int ran_after_fault = 0;
+static void *top_of_stack;
+static void *bottom_of_stack;
+
+void this_function_halts(void)
+{
+    int foo;
+    bottom_of_stack = &foo - 4;
+    /* EAX is used by compiler-generated code to
+     * increment ran_after_fault, so we need to
+     * preserve it in our asm section */
+    unsigned long saved_eax;
+
+    /* Set up registers with known values which will be tested in the signal handler */
+    __asm__ volatile("movl %%eax, %0" : "=m"(saved_eax));
+    __asm__ volatile("movl $0xfeed0101,%eax");
+    __asm__ volatile("movl $0xfeed0202,%ebx");
+    __asm__ volatile("movl $0xfeed0303,%ecx");
+    __asm__ volatile("movl $0xfeed0404,%edx");
+    __asm__ volatile("movl $0xfeed0505,%edi");
+    __asm__ volatile("movl $0xfeed0606,%esi");
+    __asm__ volatile("hlt");
+    __asm__ volatile("movl %0, %%eax" : : "m"(saved_eax));
+    ran_after_fault++;
+}
+
+void this_function_int3s(void)
+{
+    int foo;
+    bottom_of_stack = &foo - 4;
+    unsigned long saved_eax;
+
+    /* Set up registers with known values which will be tested in the signal handler */
+    __asm__ volatile("movl %%eax, %0" : "=m"(saved_eax));
+    __asm__ volatile("movl $0xfeed0101,%eax");
+    __asm__ volatile("movl $0xfeed0202,%ebx");
+    __asm__ volatile("movl $0xfeed0303,%ecx");
+    __asm__ volatile("movl $0xfeed0404,%edx");
+    __asm__ volatile("movl $0xfeed0505,%edi");
+    __asm__ volatile("movl $0xfeed0606,%esi");
+    __asm__ volatile("int $3");
+    __asm__ volatile("movl %0, %%eax" : : "m"(saved_eax));
+    ran_after_fault++;
+}
+
+
+static void
+handle_signal(int sig, siginfo_t *si, void *vuc)
+{
+    ucontext_t *uc = (ucontext_t *)vuc;
+
+    if (verbose)
+    {
+       fprintf(stderr, "handle_signal\n");
+       fflush(stderr);
+    }
+
+    sig_count++;
+    ASSERT(sig_count == 1);
+
+    int expected_sig = (using_int3 ? SIGTRAP : SIGSEGV);
+    ASSERT_EQ(sig, expected_sig);
+    ASSERT_NE(si, NULL);
+    ASSERT_NE(uc, NULL);
+    ASSERT_NE(uc->uc_mcontext, NULL);
+
+    /* Test that the siginfo is set up right for this signal */
+    ASSERT_EQ(si->si_signo, expected_sig);
+    ASSERT_EQ(si->si_errno, 0);
+    int expected_code = (using_int3 ? 1 : 0);
+    ASSERT_EQ(si->si_code, expected_code);
+    ASSERT_EQ(si->si_pid, 0);
+    ASSERT_EQ(si->si_uid, 0);
+    ASSERT_EQ(si->si_status, 0);
+    ASSERT_EQ(si->si_addr, 0);
+    ASSERT_EQ(si->si_band, 0);
+
+    /* Test that various registers were saved in the signal ucontext */
+    ASSERT_EQ(uc->uc_mcontext->__ss.__eax, 0xfeed0101);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__ebx, 0xfeed0202);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__ecx, 0xfeed0303);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__edx, 0xfeed0404);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__edi, 0xfeed0505);
+    ASSERT_EQ(uc->uc_mcontext->__ss.__esi, 0xfeed0606);
+
+    /* Test that the saved EBP and ESP point into roughly the right
+     * part of the stack */
+    ASSERT_GTE(uc->uc_mcontext->__ss.__ebp, bottom_of_stack);
+    ASSERT_LTE(uc->uc_mcontext->__ss.__ebp, top_of_stack);
+    ASSERT_GTE(uc->uc_mcontext->__ss.__esp, bottom_of_stack);
+    ASSERT_LTE(uc->uc_mcontext->__ss.__esp, top_of_stack);
+
+    /* Test that the saved EIP points into roughly the
+     * right part of the text segment */
+    char *calling_fn = (using_int3 ? (char *)&this_function_int3s : (char *)&this_function_halts);
+    ASSERT_GTE(uc->uc_mcontext->__ss.__eip, calling_fn);
+    ASSERT_LTE(uc->uc_mcontext->__ss.__eip, calling_fn+400);
+
+    /*
+    printf("       RFLAGS 0x%016llx\n", (unsigned long long)uc->uc_mcontext->__ss.__rflags);
+    */
+
+    /*
+     * Test that the EIP is restored from the signal ucontext;
+     * this should skip past the HLT/INT instruction and
+     * allow execution to continue back out to main()
+     */
+    if (verbose)
+    {
+       fprintf(stderr, "Setting up to return past the HLT\n");
+       fflush(stderr);
+    }
+    uc->uc_mcontext->__ss.__eip += (using_int3 ? 0 : 1);
+
+    if (verbose)
+    {
+       fprintf(stderr, "Returning from signal handler\n");
+       fflush(stderr);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    int r;
+    struct sigaction act;
+
+    top_of_stack = (void *)&act;
+
+    if (argc > 1 && !strcmp(argv[1], "--verbose"))
+       verbose = 1;
+
+    if (verbose)
+       printf("Setting up signal handler\n");
+    memset(&act, 0, sizeof(act));
+    act.sa_sigaction = handle_signal;
+    act.sa_flags |= SA_SIGINFO;
+    if (RUNNING_ON_VALGRIND)
+       using_int3 = true;
+    r = sigaction((using_int3 ? SIGTRAP : SIGSEGV), &act, NULL);
+    ASSERT_EQ(r, 0);
+
+    if (verbose)
+    {
+       fprintf(stderr, "Calling function with a breakpoint insn in it\n");
+       fflush(stderr);
+    }
+    if (using_int3)
+       this_function_int3s();
+    else
+       this_function_halts();
+    ASSERT_EQ(ran_after_fault, 1);
+
+    fprintf(stderr, "PASS\n");
+    return 0;
+}
diff --git a/none/tests/x86-darwin/bug341419.stderr.exp b/none/tests/x86-darwin/bug341419.stderr.exp
new file mode 100644 (file)
index 0000000..7ef22e9
--- /dev/null
@@ -0,0 +1 @@
+PASS
diff --git a/none/tests/x86-darwin/bug341419.vgtest b/none/tests/x86-darwin/bug341419.vgtest
new file mode 100644 (file)
index 0000000..baae689
--- /dev/null
@@ -0,0 +1,3 @@
+prog: bug341419
+vgopts: -q
+cleanup: rm -f vgcore.*
diff --git a/none/tests/x86-darwin/filter_stderr b/none/tests/x86-darwin/filter_stderr
new file mode 100755 (executable)
index 0000000..587754a
--- /dev/null
@@ -0,0 +1,11 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+# Remove ==pid== and --pid-- and **pid** strings 
+perl -p -e 's/(==|--|\*\*)[0-9]{1,7}\1 //' |
+
+perl -p -e 's/0x[0-9A-Fa-f]+/0x......../g'
+
+# NOTE: it is essential for the bug345887 testcase that the stderr
+#       filtering does *not* remove lines beginning with --