From 944e39803dc4904223f5037dc6d2e645556758ba Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Tue, 8 Oct 2013 21:26:00 +0000 Subject: [PATCH] i#58 MacOS: Mac signal handling code, part 1: Puts some pieces in place, like the signal lists, but is missing context and floating-point support. Added assert that sigset struct matches int for the type difference. SVN-Revision: 2313 --- core/CMakeLists.txt | 1 + core/lib/globals_shared.h | 10 +++ core/unix/os_exports.h | 10 ++- core/unix/signal.c | 66 +++++++++++++---- core/unix/signal_macos.c | 142 +++++++++++++++++++++++++++++++++++++ core/unix/signal_private.h | 61 +++++++++++++--- 6 files changed, 268 insertions(+), 22 deletions(-) create mode 100644 core/unix/signal_macos.c diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index e636dc2bbc2..c00f52e7f12 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -174,6 +174,7 @@ if (UNIX) set(OS_SRCS ${OS_SRCS} unix/memquery_macos.c) set(OS_SRCS ${OS_SRCS} unix/ksynch_macos.c) set(OS_SRCS ${OS_SRCS} unix/tls_macos.c) + set(OS_SRCS ${OS_SRCS} unix/signal_macos.c) elseif (VMKERNEL) set(VMKUW_DIR ${PROJECT_SOURCE_DIR}/../internal/core/linux) include_directories(${VMKUW_DIR}) diff --git a/core/lib/globals_shared.h b/core/lib/globals_shared.h index 1f75f88f60d..d5292898adc 100644 --- a/core/lib/globals_shared.h +++ b/core/lib/globals_shared.h @@ -457,6 +457,16 @@ typedef struct _instr_t instr_t; # define IF_LINUX_(x) #endif +#ifdef MACOS +# define IF_MACOS(x) x +# define IF_MACOS_ELSE(x,y) x +# define IF_MACOS_(x) x, +#else +# define IF_MACOS(x) +# define IF_MACOS_ELSE(x,y) y +# define IF_MACOS_(x) +#endif + #ifdef HAVE_MEMINFO_QUERY # define IF_MEMQUERY(x) x # define IF_MEMQUERY_(x) x, diff --git a/core/unix/os_exports.h b/core/unix/os_exports.h index 7ecf5a044bc..3e3347d594f 100644 --- a/core/unix/os_exports.h +++ b/core/unix/os_exports.h @@ -209,7 +209,11 @@ bool unhook_vsyscall(void); #define NUM_NONRT 32 /* includes 0 */ #define OFFS_RT 32 -#define NUM_RT 33 /* RT signals are [32..64] inclusive, hence 33. */ +#ifdef LINUX +# define NUM_RT 33 /* RT signals are [32..64] inclusive, hence 33. */ +#else +# define NUM_RT 0 /* no RT signals */ +#endif /* MAX_SIGNUM is the highest valid signum. */ #define MAX_SIGNUM ((OFFS_RT) + (NUM_RT) - 1) /* i#336: MAX_SIGNUM is a valid signal, so we must allocate space for it. @@ -229,7 +233,11 @@ bool unhook_vsyscall(void); * each (-> 8 bytes vs. 128 bytes) */ typedef struct _kernel_sigset_t { +#ifdef LINUX unsigned long sig[_NSIG_WORDS]; +#elif defined(MACOS) + unsigned int sig[_NSIG_WORDS]; +#endif } kernel_sigset_t; void receive_pending_signal(dcontext_t *dcontext); diff --git a/core/unix/signal.c b/core/unix/signal.c index 604bfd3209c..3f09357ce42 100644 --- a/core/unix/signal.c +++ b/core/unix/signal.c @@ -45,8 +45,16 @@ #include "signal_private.h" /* pulls in globals.h for us, in right order */ -#if !defined(LINUX) && !defined(MACOS) -# error Unknown operating system +#ifdef LINUX +/* We want to build on older toolchains so we have our own copy of signal + * data structures + */ +# include "include/sigcontext.h" +# include "include/signalfd.h" +# include "../globals.h" /* after our sigcontext.h, to preclude bits/sigcontext.h */ +#elif defined(MACOS) +# include "../globals.h" /* this defines _XOPEN_SOURCE for Mac */ +# include /* after globals.h, for _XOPEN_SOURCE from os_exports.h */ #endif #ifdef LINUX @@ -58,7 +66,6 @@ #include #include #include /* for memcpy and memset */ -#include "../globals.h" #include "os_private.h" #include "../fragment.h" #include "../fcache.h" @@ -84,6 +91,12 @@ # include #endif +#ifdef MACOS +/* Define the Linux names, which the code is already using */ +# define SA_NOMASK SA_NODEFER +# define SA_ONESHOT SA_RESETHAND +#endif + /**** data structures ***************************************************/ /* The signal numbers are slightly different between operating systems. @@ -117,9 +130,13 @@ sig_is_alarm_signal(int sig) #define SA_RESTORER 0x04000000 /* if no app sigaction, it's RT, since that's our handler */ -#define IS_RT_FOR_APP(info, sig) \ +#ifdef LINUX +# define IS_RT_FOR_APP(info, sig) \ IF_X64_ELSE(true, ((info)->app_sigaction[(sig)] == NULL ? true : \ (TEST(SA_SIGINFO, (info)->app_sigaction[(sig)]->flags)))) +#elif defined(MACOS) +# define IS_RT_FOR_APP(info, sig) (true) +#endif /* kernel sets size and sp to 0 for SS_DISABLE * when asked, will hand back SS_ONSTACK only if current xsp is inside the @@ -135,14 +152,28 @@ sig_is_alarm_signal(int sig) * assume the stack pointer is 4-aligned already, so we over estimate padding * size by the alignment minus 4. */ +#ifdef LINUX /* An extra 4 for trailing FP_XSTATE_MAGIC2 */ -#define AVX_FRAME_EXTRA (sizeof(struct _xstate) + AVX_ALIGNMENT - 4 + 4) -#define FPSTATE_FRAME_EXTRA (sizeof(struct _fpstate) + FPSTATE_ALIGNMENT - 4) -#define XSTATE_FRAME_EXTRA (YMM_ENABLED() ? AVX_FRAME_EXTRA : FPSTATE_FRAME_EXTRA) - -#define AVX_DATA_SIZE (sizeof(struct _xstate) + 4) -#define FPSTATE_DATA_SIZE (sizeof(struct _fpstate)) -#define XSTATE_DATA_SIZE (YMM_ENABLED() ? AVX_DATA_SIZE : FPSTATE_DATA_SIZE) +# define AVX_FRAME_EXTRA (sizeof(struct _xstate) + AVX_ALIGNMENT - 4 + 4) +# define FPSTATE_FRAME_EXTRA (sizeof(struct _fpstate) + FPSTATE_ALIGNMENT - 4) +# define XSTATE_FRAME_EXTRA (YMM_ENABLED() ? AVX_FRAME_EXTRA : FPSTATE_FRAME_EXTRA) + +# define AVX_DATA_SIZE (sizeof(struct _xstate) + 4) +# define FPSTATE_DATA_SIZE (sizeof(struct _fpstate)) +# define XSTATE_DATA_SIZE (YMM_ENABLED() ? AVX_DATA_SIZE : FPSTATE_DATA_SIZE) + +#elif defined(MACOS) +/* Currently assuming __darwin_mcontext_avx{32,64} is always used in the + * frame. If instead __darwin_mcontext{32,64} is used (w/ just float and no AVX) + * on, say, older machines or OSX versions, we'll have to revisit this. + */ +# define AVX_FRAME_EXTRA 0 +# define FPSTATE_FRAME_EXTRA 0 +# define XSTATE_FRAME_EXTRA 0 +# define AVX_DATA_SIZE 0 +# define FPSTATE_DATA_SIZE 0 +# define XSTATE_DATA_SIZE 0 +#endif /* If we only intercept a few signals, we leave whether un-intercepted signals * are blocked unchanged and stored in the kernel. If we intercept all (not @@ -356,6 +387,7 @@ void signal_init() { IF_LINUX(IF_X64(ASSERT(ALIGNED(offsetof(sigpending_t, xstate), AVX_ALIGNMENT)))); + IF_MACOS(ASSERT(sizeof(kernel_sigset_t) == sizeof(__darwin_sigset_t))); os_itimers_thread_shared(); /* Set up a handler for safe_read (or other fault detection) during @@ -1772,13 +1804,17 @@ thread_set_self_context(void *cxt) * kernel 2.6.23.9 at least so we leave frame.uc.uc_stack as all zeros. */ /* make sure sigreturn's mask setting doesn't change anything */ - sigprocmask_syscall(SIG_SETMASK, NULL, &frame.uc.uc_sigmask, + sigprocmask_syscall(SIG_SETMASK, NULL, (kernel_sigset_t *) &frame.uc.uc_sigmask, sizeof(frame.uc.uc_sigmask)); LOG(THREAD_GET, LOG_ASYNCH, 2, "thread_set_self_context: pc="PFX"\n", sc->SC_XIP); /* set up xsp to point at &frame + sizeof(char*) */ xsp_for_sigreturn = ((app_pc)&frame) + sizeof(char*); asm("mov %0, %%"ASM_XSP : : "m"(xsp_for_sigreturn)); +#ifdef MACOS + asm("jmp _dynamorio_sigreturn"); +#else asm("jmp dynamorio_sigreturn"); +#endif ASSERT_NOT_REACHED(); } @@ -2090,6 +2126,8 @@ fixup_rtframe_pointers(dcontext_t *dcontext, int sig, # endif /* 32-bit kernel copies to aligned buf first */ IF_X64(ASSERT(ALIGNED(f_new->uc.uc_mcontext.fpstate, 16))); +#elif defined(MACOS) + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#85: fix up uc_mcontext ptr */ #endif /* LINUX */ } @@ -5249,7 +5287,11 @@ handle_suspend_signal(dcontext_t *dcontext, kernel_ucontext_t *ucxt) #endif } else { ksynch_set_value(&ostd->terminated, 1); +#ifdef MACOS + asm("jmp _dynamorio_sys_exit"); +#else asm("jmp dynamorio_sys_exit"); +#endif } ASSERT_NOT_REACHED(); return false; diff --git a/core/unix/signal_macos.c b/core/unix/signal_macos.c new file mode 100644 index 00000000000..b18c33d0026 --- /dev/null +++ b/core/unix/signal_macos.c @@ -0,0 +1,142 @@ +/* ******************************************************************************* + * Copyright (c) 2013 Google, Inc. All rights reserved. + * *******************************************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of VMware, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +/* + * signal_macos.c - MacOS-specific signal code + * + * FIXME i#58: NYI (see comments below as well): + * + many pieces are not at all implemented, but it should be straightforward + * + longer-term i#1291: use raw syscalls instead of libSystem wrappers + */ + +#include "signal_private.h" /* pulls in globals.h for us, in right order */ + +#ifndef MACOS +# error Mac-only +#endif + +/* based on xnu bsd/sys/signalvar.h */ +int default_action[] = { + 0, /* 0 unused */ + DEFAULT_TERMINATE, /* 1 SIGHUP */ + DEFAULT_TERMINATE, /* 2 SIGINT */ + DEFAULT_TERMINATE_CORE, /* 3 SIGQUIT */ + DEFAULT_TERMINATE_CORE, /* 4 SIGILL */ + DEFAULT_TERMINATE_CORE, /* 5 SIGTRAP */ + DEFAULT_TERMINATE_CORE, /* 6 SIGABRT/SIGIOT */ + DEFAULT_TERMINATE_CORE, /* 7 SIGEMT/SIGPOLL */ + DEFAULT_TERMINATE_CORE, /* 8 SIGFPE */ + DEFAULT_TERMINATE, /* 9 SIGKILL */ + DEFAULT_TERMINATE_CORE, /* 10 SIGBUS */ + DEFAULT_TERMINATE_CORE, /* 11 SIGSEGV */ + DEFAULT_TERMINATE_CORE, /* 12 SIGSYS */ + DEFAULT_TERMINATE, /* 13 SIGPIPE */ + DEFAULT_TERMINATE, /* 14 SIGALRM */ + DEFAULT_TERMINATE, /* 15 SIGTERM */ + DEFAULT_IGNORE, /* 16 SIGURG */ + DEFAULT_STOP, /* 17 SIGSTOP */ + DEFAULT_STOP, /* 18 SIGTSTP */ + DEFAULT_CONTINUE, /* 19 SIGCONT */ + DEFAULT_IGNORE, /* 20 SIGCHLD */ + DEFAULT_STOP, /* 21 SIGTTIN */ + DEFAULT_STOP, /* 22 SIGTTOU */ + DEFAULT_IGNORE, /* 23 SIGIO */ + DEFAULT_TERMINATE, /* 24 SIGXCPU */ + DEFAULT_TERMINATE, /* 25 SIGXFSZ */ + DEFAULT_TERMINATE, /* 26 SIGVTALRM */ + DEFAULT_TERMINATE, /* 27 SIGPROF */ + DEFAULT_IGNORE, /* 28 SIGWINCH */ + DEFAULT_IGNORE, /* 29 SIGINFO */ + DEFAULT_TERMINATE, /* 30 SIGUSR1 */ + DEFAULT_TERMINATE, /* 31 SIGUSR2 */ + /* no real-time support */ +}; + +bool can_always_delay[] = { + true, /* 0 unused */ + true, /* 1 SIGHUP */ + true, /* 2 SIGINT */ + true, /* 3 SIGQUIT */ + false, /* 4 SIGILL */ + false, /* 5 SIGTRAP */ + false, /* 6 SIGABRT/SIGIOT */ + true, /* 7 SIGEMT/SIGPOLL */ + false, /* 8 SIGFPE */ + true, /* 9 SIGKILL */ + false, /* 10 SIGBUS */ + false, /* 11 SIGSEGV */ + false, /* 12 SIGSYS */ + false, /* 13 SIGPIPE */ + true, /* 14 SIGALRM */ + true, /* 15 SIGTERM */ + true, /* 16 SIGURG */ + true, /* 17 SIGSTOP */ + true, /* 18 SIGTSTP */ + true, /* 19 SIGCONT */ + true, /* 20 SIGCHLD */ + true, /* 21 SIGTTIN */ + true, /* 22 SIGTTOU */ + true, /* 23 SIGIO */ + false, /* 24 SIGXCPU */ + true, /* 25 SIGXFSZ */ + true, /* 26 SIGVTALRM */ + true, /* 27 SIGPROF */ + true, /* 28 SIGWINCH */ + true, /* 29 SIGINFO */ + true, /* 30 SIGUSR1 */ + true, /* 31 SIGUSR2 */ + /* no real-time support */ +}; + +void +save_fpstate(dcontext_t *dcontext, sigframe_rt_t *frame) +{ + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#58: MacOS signal handling NYI */ +} + +void +sigcontext_to_mcontext_mm(priv_mcontext_t *mc, sigcontext_t *sc) +{ + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#58: MacOS signal handling NYI */ +} + +void +mcontext_to_sigcontext_mm(sigcontext_t *sc, priv_mcontext_t *mc) +{ + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#58: MacOS signal handling NYI */ +} + +void +dump_sigcontext(dcontext_t *dcontext, sigcontext_t *sc) +{ + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#58: MacOS signal handling NYI */ +} diff --git a/core/unix/signal_private.h b/core/unix/signal_private.h index 8a684f37a36..c3a0438f434 100644 --- a/core/unix/signal_private.h +++ b/core/unix/signal_private.h @@ -93,11 +93,19 @@ enum { */ struct _kernel_sigaction_t { handler_t handler; +#ifdef LINUX unsigned long flags; void (*restorer)(void); kernel_sigset_t mask; +#elif defined(MACOS) + /* this is struct __sigaction in sys/signal.h */ + void (*restorer)(void); + kernel_sigset_t mask; + int flags; +#endif }; /* typedef in os_private.h */ +#ifdef LINUX /* kernel's notion of ucontext is different from glibc's! * this is adapted from asm/ucontext.h: */ @@ -105,13 +113,25 @@ typedef struct { unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; - sigcontext_t uc_mcontext; + sigcontext_t uc_mcontext; kernel_sigset_t uc_sigmask; /* mask last for extensibility */ } kernel_ucontext_t; -#define SIGCXT_FROM_UCXT(ucxt) (&((ucxt)->uc_mcontext)) -#define SIGMASK_FROM_UCXT(ucxt) (&((ucxt)->uc_sigmask)) +# define SIGCXT_FROM_UCXT(ucxt) (&((ucxt)->uc_mcontext)) +# define SIGMASK_FROM_UCXT(ucxt) (&((ucxt)->uc_sigmask)) +#elif defined(MACOS) +# ifdef X64 +typedef _STRUCT_UCONTEXT64 /* == __darwin_ucontext64 */ kernel_ucontext_t; +# define SIGCXT_FROM_UCXT(ucxt) ((ucxt)->uc_mcontext64) +# else +typedef _STRUCT_UCONTEXT /* == __darwin_ucontext */ kernel_ucontext_t; +# define SIGCXT_FROM_UCXT(ucxt) ((ucxt)->uc_mcontext) +# endif +# define SIGMASK_FROM_UCXT(ucxt) ((kernel_sigset_t*)&((ucxt)->uc_sigmask)) +#endif + +#ifdef LINUX /* we assume frames look like this, with rt_sigframe used if SA_SIGINFO is set * (these are from /usr/src/linux/arch/i386/kernel/signal.c for kernel 2.4.17) */ @@ -141,19 +161,23 @@ typedef struct sigframe { int sig_noclobber; /* In 2.6.28+, fpstate/xstate goes here */ } sigframe_plain_t; +#else +/* Mac only has one frame type, with a libc stub that calls 1-arg or 3-arg handler */ +#endif /* the rt frame is used for SA_SIGINFO signals */ typedef struct rt_sigframe { +#ifdef LINUX char *pretcode; -#ifdef X64 -# ifdef VMX86_SERVER +# ifdef X64 +# ifdef VMX86_SERVER siginfo_t info; kernel_ucontext_t uc; -# else +# else kernel_ucontext_t uc; siginfo_t info; -# endif -#else +# endif +# else int sig; siginfo_t *pinfo; void *puc; @@ -167,8 +191,27 @@ typedef struct rt_sigframe { * pointer in the sigcontext anyway. */ char retcode[RETCODE_SIZE]; -#endif +# endif /* In 2.6.28+, fpstate/xstate goes here */ + +#elif defined(MACOS) +# ifdef X64 + /* kernel places padding to align to 16, and then puts retaddr slot */ + struct __darwin_mcontext_avx64 mc; /* "struct mcontext_avx64" to kernel */ + siginfo_t info; /* matches user-mode sys/signal.h struct */ + struct __darwin_ucontext64 uc; /* "struct user_ucontext64" to kernel */ +# else + app_pc retaddr; + app_pc handler; + int sigstyle; /* UC_TRAD = 1-arg, UC_FLAVOR = 3-arg handler */ + int sig; + siginfo_t *pinfo; + struct __darwin_ucontext *puc; /* "struct user_ucontext32 *" to kernel */ + struct __darwin_mcontext_avx32 mc; /* "struct mcontext_avx32" to kernel */ + siginfo_t info; /* matches user-mode sys/signal.h struct */ + struct __darwin_ucontext uc; /* "struct user_ucontext32" to kernel */ +# endif +#endif } sigframe_rt_t; /* we have to queue up both rt and non-rt signals because we delay