* Copyright (c) 2011-2023 Google, Inc. All rights reserved.
* Copyright (c) 2008-2010 VMware, 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_private.h - declarations shared among signal handling files, but not
* exported to the rest of the code
*/
#ifndef _SIGNAL_PRIVATE_H_
#define _SIGNAL_PRIVATE_H_ 1
#include "configure.h"
* data structures.
*/
#include "include/siginfo.h"
#ifdef LINUX
# include "include/sigcontext.h"
# include "include/signalfd.h"
# include "../globals.h"
#elif defined(MACOS)
# include "../globals.h"
# include <signal.h>
# ifdef X64
# include <sys/_types/_ucontext64.h>
# endif
#endif
#include "os_private.h"
* MISC DEFINITIONS
*/
typedef void (*handler_t)(int, kernel_siginfo_t *, void *);
#ifdef MACOS
typedef void (*tramp_t)(handler_t, int, int, kernel_siginfo_t *, void *);
# define SIGHAND_STYLE_UC_TRAD 1
# define SIGHAND_STYLE_UC_FLAVOR 30
#endif
enum {
DEFAULT_TERMINATE,
DEFAULT_TERMINATE_CORE,
DEFAULT_IGNORE,
DEFAULT_STOP,
DEFAULT_CONTINUE,
};
#ifdef X86
* xrestore on sigreturn so we have to obey alignment for avx.
*/
# define AVX_ALIGNMENT 64
# define FPSTATE_ALIGNMENT 16
# define XSTATE_ALIGNMENT (YMM_ENABLED() ? AVX_ALIGNMENT : FPSTATE_ALIGNMENT)
#else
# define XSTATE_ALIGNMENT REGPARM_END_ALIGN
#endif
* FRAMES
*/
* used in glibc (I looked at glibc-2.2.4/sysdeps/unix/sysv/linux/i386/sigaction.c)
* also, /usr/include/asm/signal.h lists both versions
* I deliberately give kernel_sigaction_t's fields different names to help
* avoid confusion.
* (2.1.20 kernel has mask as 2nd field instead, and is expected to be passed
* in to the non-rt sigaction() call, which we do not yet support)
*/
struct _kernel_sigaction_t {
handler_t handler;
#ifdef LINUX
unsigned long flags;
void (*restorer)(void);
kernel_sigset_t mask;
#elif defined(MACOS)
tramp_t tramp;
kernel_sigset_t mask;
int flags;
#endif
};
#ifdef MACOS
* For simplicity we don't change the signature for the handle_sigaction routines.
*/
struct _prev_sigaction_t {
handler_t handler;
kernel_sigset_t mask;
int flags;
};
#endif
#ifdef LINUX
# define SIGACT_PRIMARY_HANDLER(sigact) (sigact)->handler
#elif defined(MACOS)
# define SIGACT_PRIMARY_HANDLER(sigact) (sigact)->tramp
#endif
#ifdef LINUX
typedef unsigned int old_sigset_t;
struct _old_sigaction_t {
handler_t handler;
old_sigset_t mask;
unsigned long flags;
void (*restorer)(void);
};
* this is adapted from asm/ucontext.h:
*/
typedef struct {
# if defined(X86)
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
sigcontext_t uc_mcontext;
kernel_sigset_t uc_sigmask;
# elif defined(AARCH64)
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
kernel_sigset_t uc_sigmask;
unsigned char sigset_ex[1024 / 8 - sizeof(kernel_sigset_t)];
sigcontext_t uc_mcontext;
# elif defined(ARM)
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
sigcontext_t uc_mcontext;
kernel_sigset_t uc_sigmask;
int sigset_ex[32 - (sizeof(kernel_sigset_t) / sizeof(int))];
union {
unsigned long uc_regspace[128] __attribute__((__aligned__(8)));
kernel_vfp_sigframe_t uc_vfp;
} coproc;
# elif defined(RISCV64)
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
kernel_sigset_t uc_sigmask;
unsigned char sigset_ex[1024 / 8 - sizeof(kernel_sigset_t)];
sigcontext_t uc_mcontext;
# else
# error NYI
# endif
} kernel_ucontext_t;
# define SIGMASK_FROM_UCXT(ucxt) (&((ucxt)->uc_sigmask))
#elif defined(MACOS)
# ifdef X64
typedef _STRUCT_UCONTEXT64 kernel_ucontext_t;
# else
typedef _STRUCT_UCONTEXT kernel_ucontext_t;
# endif
# define SIGMASK_FROM_UCXT(ucxt) ((kernel_sigset_t *)&((ucxt)->uc_sigmask))
#endif
#if defined(LINUX) || defined(X64)
# define SIGINFO_FROM_RT_FRAME(frame) (&(frame)->info)
#elif defined(MACOS)
* location in our frame struct doesn't exactly match the kernel due to
* the mid padding.
*/
# define SIGINFO_FROM_RT_FRAME(frame) ((frame)->pinfo)
#endif
#ifdef LINUX
* (these are from /usr/src/linux/arch/i386/kernel/signal.c for kernel 2.4.17)
*/
# define RETCODE_SIZE 8
typedef struct sigframe {
# ifdef X86
char *pretcode;
int sig;
sigcontext_t sc;
* is at the end of the struct so it can include xstate
*/
kernel_fpstate_t fpstate;
unsigned long extramask[_NSIG_WORDS - 1];
char retcode[RETCODE_SIZE];
# elif defined(ARM)
kernel_ucontext_t uc;
char retcode[RETCODE_SIZE];
# endif
* the kernel's...but where else can I store sig where the app won't
* clobber it?
* WARNING: our handler receives only rt frames, and we construct
* plain frames but never pass them to the kernel (on sigreturn() we
* just go to new context and interpret from there), so the only
* transparency problem here is if app tries to build its own plain
* frame and call sigreturn() unrelated to signal delivery.
* UPDATE: actually we do invoke SYS_*sigreturn
*/
int sig_noclobber;
} sigframe_plain_t;
#else
#endif
typedef struct rt_sigframe {
#ifdef LINUX
# ifdef X86
char *pretcode;
# ifdef X64
# ifdef VMX86_SERVER
kernel_siginfo_t info;
kernel_ucontext_t uc;
# else
kernel_ucontext_t uc;
kernel_siginfo_t info;
# endif
# else
int sig;
kernel_siginfo_t *pinfo;
void *puc;
kernel_siginfo_t info;
kernel_ucontext_t uc;
* try to reproduce that exact layout and detect the underlying kernel
* (the safest way would be to send ourselves a signal and examine the
* frame, rather than relying on uname, to handle backports), we use
* the new layout even on old kernels. The app should use the fpstate
* pointer in the sigcontext anyway.
*/
char retcode[RETCODE_SIZE];
# endif
# elif defined(AARCHXX)
kernel_siginfo_t info;
kernel_ucontext_t uc;
char retcode[RETCODE_SIZE];
# elif defined(RISCV64)
kernel_siginfo_t info;
kernel_ucontext_t uc;
char retcode[RETCODE_SIZE];
# endif
#elif defined(MACOS)
# ifdef AARCH64
kernel_siginfo_t info;
struct __darwin_ucontext64 uc;
struct __darwin_mcontext64 mc;
# elif defined(X64)
* and then skips the retaddr slot to align to 8.
*/
* enabled. Given that it's inlined here *first*, though, we need to figure
* out how best to handle this variability. Multiple sigframe_rt_t struct
* definitions? Do we want a discovery signal to find the size at init time
* like on Linux? We would get the size by counting from "info".
* Also, should we change this to sigcontext_t.
*/
struct __darwin_mcontext_avx64 mc;
kernel_siginfo_t info;
struct __darwin_ucontext64 uc;
# else
app_pc retaddr;
app_pc handler;
int sigstyle;
int sig;
kernel_siginfo_t *pinfo;
struct __darwin_ucontext *puc;
* for retaddr post-call alignment, so don't access these subsequent fields
* directly if given a frame from the kernel!
*/
struct __darwin_mcontext_avx32 mc;
kernel_siginfo_t info;
struct __darwin_ucontext uc;
# endif
#endif
} sigframe_rt_t;
* their delivery.
* PR 304708: we now leave in rt form right up until we copy to the
* app stack, so that we can deliver to a client at a safe spot
* in rt form.
*/
typedef struct _sigpending_t {
sigframe_rt_t rt_frame;
byte *access_address;
bool use_sigcontext;
bool unblocked_at_receipt;
struct _sigpending_t *next;
#if defined(LINUX) && defined(X86)
* if we delay we need to ensure we have room for it.
* we statically keep room for full xstate in case we need it.
*/
kernel_xstate_t __attribute__((aligned(AVX_ALIGNMENT))) xstate;
* which we handle here by placing it last.
*/
#endif
} sigpending_t;
size_t
signal_frame_extra_size(bool include_alignment);
* PER-THREAD DATA
*/
typedef struct _itimer_info_t {
uint64 interval;
uint64 value;
} itimer_info_t;
typedef struct _thread_itimer_info_t {
* in separate threads simultaneously (we don't want to block on itimer
* locks to handle app-syscall-interruption cases). Xref i#2993.
* We only need owner info -- xref i#219: we should add a known-owner
* lock for cases where a full-fledged recursive lock is not needed.
*/
recursive_lock_t lock;
itimer_info_t app;
itimer_info_t app_saved;
itimer_info_t dr;
itimer_info_t actual;
void (*cb)(dcontext_t *, priv_mcontext_t *);
void (*cb_api)(dcontext_t *, dr_mcontext_t *);
} thread_itimer_info_t;
* for -prof_pcs, and ITIMER_PROF for PAPI
*/
#define NUM_ITIMERS 3
#define SKIP_ALARM_XL8_MAX 3
struct _sigfd_pipe_t;
typedef struct _sigfd_pipe_t sigfd_pipe_t;
* Typically this is the whole thread group or "process".
* The thread_sig_info_t for each thread in the group points to a
* single copy of this structure.
*/
typedef struct _sighand_info_t {
bool is_shared;
int refcount;
mutex_t lock;
* between it and the libc version.
*/
kernel_sigaction_t *action[SIGARRAY_SIZE];
bool we_intercept[SIGARRAY_SIZE];
* a signal in a thread for which it is blocked, we need to know whether it was
* a "process"-wide signal and whether some other thread has it unblocked.
* To avoid heavyweight locks every time, we keep an atomic-access counter of
* unmasked threads for each signal, for the CLONE_SIGHAND group (typically
* whole process).
*/
int threads_unmasked[SIGARRAY_SIZE];
} sighand_info_t;
typedef struct _thread_sig_info_t {
sighand_info_t *sighand;
* in post-syscall handling.
*/
kernel_sigaction_t prior_app_sigaction;
bool use_kernel_prior_sigaction;
* can modify it.
*/
kernel_sigaction_t our_sigaction;
const kernel_sigaction_t *sigaction_param;
* squash alarm or profiling signals up until this point.
*/
bool fully_initialized;
* usage. This info is shared across CLONE_THREAD threads only for
* NPTL in kernel 2.6.12+ so these fields are separately shareable from
* the CLONE_SIGHAND set of fields above.
*/
bool shared_itimer;
* dynamo_exited and need a refcount here. This is updated via
* atomic inc/dec without holding a lock (i#1993).
*/
int *shared_itimer_refcount;
* inc/dec without holding a lock (i#1993).
*/
int *shared_itimer_underDR;
thread_itimer_info_t (*itimer)[NUM_ITIMERS];
int restorer_valid[SIGARRAY_SIZE];
stack_t app_sigstack;
sigpending_t *sigpending[SIGARRAY_SIZE];
int num_pending;
bool multiple_pending_units;
bool accessing_sigpending;
bool nested_pending_ok;
* We need to keep this in sync with the thread-group-shared
* sighand->threads_unmasked.
*
* reroute_to_unmasked_thread() needs read access to app_sigblocked from other
* threads. However, we also need lockless read access from our signal handler.
* Since all writes are from the owning thread, we read w/o a lock from the owning
* thread, but use the lock for writes from the owning thread and reads from
* other threads. (The bitwise operations make it difficult to use atomic
* updates instead of a mutex.)
*/
kernel_sigset_t app_sigblocked;
mutex_t sigblocked_lock;
* app signal handler. We can't know for sure when a handler ends if the
* app exits with a longjmp instead of siglongjmp.
*/
bool in_app_handler;
kernel_sigset_t pre_syscall_app_sigblocked;
* mask supporting ppoll, epoll_pwait and pselect
*/
kernel_sigset_t pre_syscall_app_sigprocmask;
bool pre_syscall_app_sigprocmask_valid;
* every nth signal since coarse translation is expensive (PR 213040)
*/
uint skip_alarm_xl8;
sigfd_pipe_t *signalfd[SIGARRAY_SIZE];
bool in_sigsuspend;
kernel_sigset_t app_sigblocked_save;
volatile int num_unstarted_children;
mutex_t child_lock;
stack_t sigstack;
void *sigheap;
fragment_t *interrupted;
cache_pc interrupted_pc;
#if defined(X86) && defined(LINUX)
* it is over 2K) we use a copy on the heap. There are paths where we
* can't easily free it locally so we keep a pointer in the TLS.
*/
byte *xstate_buf;
byte *xstate_alloc;
#endif
#ifdef RETURN_AFTER_CALL
app_pc signal_restorer_retaddr;
#endif
} thread_sig_info_t;
* GENERAL ROUTINES (in signal.c)
*/
sigcontext_t *
get_sigcontext_from_rt_frame(sigframe_rt_t *frame);
* We stick with the struct-containing-uint to simplify the helpers here.
*/
static inline void
kernel_sigemptyset(kernel_sigset_t *set)
{
memset(set, 0, sizeof(kernel_sigset_t));
}
static inline void
kernel_sigfillset(kernel_sigset_t *set)
{
memset(set, -1, sizeof(kernel_sigset_t));
}
static inline void
kernel_sigaddset(kernel_sigset_t *set, int _sig)
{
uint sig = _sig - 1;
if (_NSIG_WORDS == 1)
set->sig[0] |= 1UL << sig;
else
set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW);
}
static inline void
kernel_sigdelset(kernel_sigset_t *set, int _sig)
{
uint sig = _sig - 1;
if (_NSIG_WORDS == 1)
set->sig[0] &= ~(1UL << sig);
else
set->sig[sig / _NSIG_BPW] &= ~(1UL << (sig % _NSIG_BPW));
}
static inline bool
kernel_sigismember(kernel_sigset_t *set, int _sig)
{
int sig = _sig - 1;
if (_NSIG_WORDS == 1)
return CAST_TO_bool(1 & (set->sig[0] >> sig));
else
return CAST_TO_bool(1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW)));
}
static inline void
copy_kernel_sigset_to_sigset(kernel_sigset_t *kset, sigset_t *uset)
{
int sig;
#ifdef DEBUG
int rc =
#endif
sigemptyset(uset);
ASSERT(rc == 0);
* structure of user sigset_t
*/
for (sig = 1; sig <= MAX_SIGNUM; sig++) {
if (kernel_sigismember(kset, sig))
sigaddset(uset, sig);
}
}
static inline bool
libc_sigismember(const sigset_t *set, int _sig)
{
int sig = _sig - 1;
#if defined(MACOS) || defined(ANDROID)
return TEST(1UL << sig, *set);
#else
* uses __bits as the field name on sigset_t).
*/
uint bits_per = 8 * sizeof(ulong);
return TEST(1UL << (sig % bits_per), ((const ulong *)set)[sig / bits_per]);
#endif
}
static inline void
copy_sigset_to_kernel_sigset(const sigset_t *uset, kernel_sigset_t *kset)
{
int sig;
kernel_sigemptyset(kset);
for (sig = 1; sig <= MAX_SIGNUM; sig++) {
if (libc_sigismember(uset, sig))
kernel_sigaddset(kset, sig);
}
}
int
sigaction_syscall(int sig, kernel_sigaction_t *act, kernel_sigaction_t *oact);
void
set_handler_sigact(kernel_sigaction_t *act, int sig, handler_t handler);
* OS-SPECIFIC ROUTINES (in signal_<os>.c)
*/
void
signal_arch_init(void);
void
sigcontext_to_mcontext_simd(priv_mcontext_t *mc, sig_full_cxt_t *sc_full);
void
mcontext_to_sigcontext_simd(sig_full_cxt_t *sc_full, priv_mcontext_t *mc);
void
save_fpstate(dcontext_t *dcontext, sigframe_rt_t *frame);
#ifdef DEBUG
void
dump_sigcontext(dcontext_t *dcontext, sigcontext_t *sc);
#endif
#ifdef LINUX
void
signalfd_init(void);
void
signalfd_exit(void);
void
signalfd_thread_exit(dcontext_t *dcontext, thread_sig_info_t *info);
bool
notify_signalfd(dcontext_t *dcontext, thread_sig_info_t *info, int sig,
sigframe_rt_t *frame);
void
check_signals_pending(dcontext_t *dcontext, thread_sig_info_t *info);
#endif
#endif