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
#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>
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
#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)
/* 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
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);
/* 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) );
/* 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;
#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)
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
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));
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);
(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,
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;
#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
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 \
--- /dev/null
+
+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@
--- /dev/null
+/* 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;
+}
--- /dev/null
+prog: bug341419
+vgopts: -q
+cleanup: rm -f vgcore.*
--- /dev/null
+#! /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 --
--- /dev/null
+#! /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 --
--- /dev/null
+
+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@
--- /dev/null
+/* 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;
+}
--- /dev/null
+prog: bug341419
+vgopts: -q
+cleanup: rm -f vgcore.*
--- /dev/null
+#! /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 --