summaryrefslogtreecommitdiffstats
path: root/linux-user/signal-common.h
blob: 3e2dc604c2fb0b64710462d6eddd91594dde24f8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
 *  Emulation of Linux signals
 *
 *  Copyright (c) 2003 Fabrice Bellard
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#ifndef SIGNAL_COMMON_H
#define SIGNAL_COMMON_H

#include "special-errno.h"

/* Fallback addresses into sigtramp page. */
extern abi_ulong default_sigreturn;
extern abi_ulong default_rt_sigreturn;

void setup_sigtramp(abi_ulong tramp_page);

int on_sig_stack(unsigned long sp);
int sas_ss_flags(unsigned long sp);
abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka);
void target_save_altstack(target_stack_t *uss, CPUArchState *env);
abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env);

static inline void target_sigemptyset(target_sigset_t *set)
{
    memset(set, 0, sizeof(*set));
}

void host_to_target_sigset_internal(target_sigset_t *d,
                                    const sigset_t *s);
void target_to_host_sigset_internal(sigset_t *d,
                                    const target_sigset_t *s);
void tswap_siginfo(target_siginfo_t *tinfo,
                   const target_siginfo_t *info);
void set_sigmask(const sigset_t *set);
void force_sig(int sig);
void force_sigsegv(int oldsig);
void force_sig_fault(int sig, int code, abi_ulong addr);
#if defined(TARGET_ARCH_HAS_SETUP_FRAME)
void setup_frame(int sig, struct target_sigaction *ka,
                 target_sigset_t *set, CPUArchState *env);
#endif
void setup_rt_frame(int sig, struct target_sigaction *ka,
                    target_siginfo_t *info,
                    target_sigset_t *set, CPUArchState *env);

void process_pending_signals(CPUArchState *cpu_env);
void signal_init(void);
void queue_signal(CPUArchState *env, int sig, int si_type,
                  target_siginfo_t *info);
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
int target_to_host_signal(int sig);
int host_to_target_signal(int sig);
long do_sigreturn(CPUArchState *env);
long do_rt_sigreturn(CPUArchState *env);
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
                        CPUArchState *env);
int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
                        abi_ulong unew_ctx, abi_long ctx_size);
/**
 * block_signals: block all signals while handling this guest syscall
 *
 * Block all signals, and arrange that the signal mask is returned to
 * its correct value for the guest before we resume execution of guest code.
 * If this function returns non-zero, then the caller should immediately
 * return -QEMU_ERESTARTSYS to the main loop, which will take the pending
 * signal and restart execution of the syscall.
 * If block_signals() returns zero, then the caller can continue with
 * emulation of the system call knowing that no signals can be taken
 * (and therefore that no race conditions will result).
 * This should only be called once, because if it is called a second time
 * it will always return non-zero. (Think of it like a mutex that can't
 * be recursively locked.)
 * Signals will be unblocked again by process_pending_signals().
 *
 * Return value: non-zero if there was a pending signal, zero if not.
 */
int block_signals(void); /* Returns non zero if signal pending */

/**
 * process_sigsuspend_mask: read and apply syscall-local signal mask
 *
 * Read the guest signal mask from @sigset, length @sigsize.
 * Convert that to a host signal mask and save it to sigpending_mask.
 *
 * Return value: negative target errno, or zero;
 *               store &sigpending_mask into *pset on success.
 */
int process_sigsuspend_mask(sigset_t **pset, target_ulong sigset,
                            target_ulong sigsize);

/**
 * finish_sigsuspend_mask: finish a sigsuspend-like syscall
 *
 * Set in_sigsuspend if we need to use the modified sigset
 * during process_pending_signals.
 */
static inline void finish_sigsuspend_mask(int ret)
{
    if (ret != -QEMU_ERESTARTSYS) {
        TaskState *ts = (TaskState *)thread_cpu->opaque;
        ts->in_sigsuspend = 1;
    }
}

#if defined(SIGSTKFLT) && defined(TARGET_SIGSTKFLT)
#define MAKE_SIG_ENTRY_SIGSTKFLT        MAKE_SIG_ENTRY(SIGSTKFLT)
#else
#define MAKE_SIG_ENTRY_SIGSTKFLT
#endif

#if defined(SIGIOT) && defined(TARGET_SIGIOT)
#define MAKE_SIG_ENTRY_SIGIOT           MAKE_SIG_ENTRY(SIGIOT)
#else
#define MAKE_SIG_ENTRY_SIGIOT
#endif

#define MAKE_SIGNAL_LIST \
        MAKE_SIG_ENTRY(SIGHUP) \
        MAKE_SIG_ENTRY(SIGINT) \
        MAKE_SIG_ENTRY(SIGQUIT) \
        MAKE_SIG_ENTRY(SIGILL) \
        MAKE_SIG_ENTRY(SIGTRAP) \
        MAKE_SIG_ENTRY(SIGABRT) \
        MAKE_SIG_ENTRY(SIGBUS) \
        MAKE_SIG_ENTRY(SIGFPE) \
        MAKE_SIG_ENTRY(SIGKILL) \
        MAKE_SIG_ENTRY(SIGUSR1) \
        MAKE_SIG_ENTRY(SIGSEGV) \
        MAKE_SIG_ENTRY(SIGUSR2) \
        MAKE_SIG_ENTRY(SIGPIPE) \
        MAKE_SIG_ENTRY(SIGALRM) \
        MAKE_SIG_ENTRY(SIGTERM) \
        MAKE_SIG_ENTRY(SIGCHLD) \
        MAKE_SIG_ENTRY(SIGCONT) \
        MAKE_SIG_ENTRY(SIGSTOP) \
        MAKE_SIG_ENTRY(SIGTSTP) \
        MAKE_SIG_ENTRY(SIGTTIN) \
        MAKE_SIG_ENTRY(SIGTTOU) \
        MAKE_SIG_ENTRY(SIGURG) \
        MAKE_SIG_ENTRY(SIGXCPU) \
        MAKE_SIG_ENTRY(SIGXFSZ) \
        MAKE_SIG_ENTRY(SIGVTALRM) \
        MAKE_SIG_ENTRY(SIGPROF) \
        MAKE_SIG_ENTRY(SIGWINCH) \
        MAKE_SIG_ENTRY(SIGIO) \
        MAKE_SIG_ENTRY(SIGPWR) \
        MAKE_SIG_ENTRY(SIGSYS) \
        MAKE_SIG_ENTRY_SIGSTKFLT \
        MAKE_SIG_ENTRY_SIGIOT

#endif