bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 1 | /* |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 2 | * Emulation of Linux signals |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 3 | * |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 4 | * Copyright (c) 2003 Fabrice Bellard |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
Blue Swirl | 8167ee8 | 2009-07-16 20:47:01 +0000 | [diff] [blame] | 17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 18 | */ |
| 19 | #include <stdlib.h> |
| 20 | #include <stdio.h> |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 21 | #include <string.h> |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 22 | #include <stdarg.h> |
bellard | 2677e10 | 2003-04-10 00:03:27 +0000 | [diff] [blame] | 23 | #include <unistd.h> |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 24 | #include <errno.h> |
aurel32 | 603e4fd | 2009-04-15 16:18:38 +0000 | [diff] [blame] | 25 | #include <assert.h> |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 26 | #include <sys/ucontext.h> |
Mika Westerberg | edf8e2a | 2009-04-07 09:57:11 +0300 | [diff] [blame] | 27 | #include <sys/resource.h> |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 28 | |
bellard | 3ef693a | 2003-03-23 20:17:16 +0000 | [diff] [blame] | 29 | #include "qemu.h" |
blueswir1 | 7d99a00 | 2009-01-14 19:00:36 +0000 | [diff] [blame] | 30 | #include "qemu-common.h" |
Peter Maydell | da30d85 | 2011-12-05 19:42:18 +0000 | [diff] [blame] | 31 | #include "signal-common.h" |
blueswir1 | 992f48a | 2007-10-14 16:27:31 +0000 | [diff] [blame] | 32 | #include "target_signal.h" |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 33 | |
| 34 | //#define DEBUG_SIGNAL |
| 35 | |
Peter Maydell | da30d85 | 2011-12-05 19:42:18 +0000 | [diff] [blame] | 36 | struct target_sigaltstack target_sigaltstack_used = { |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 37 | .ss_sp = 0, |
| 38 | .ss_size = 0, |
| 39 | .ss_flags = TARGET_SS_DISABLE, |
| 40 | }; |
| 41 | |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 42 | static struct target_sigaction sigact_table[TARGET_NSIG]; |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 43 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 44 | static void host_signal_handler(int host_signum, siginfo_t *info, |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 45 | void *puc); |
| 46 | |
Arnaud Patard | 3ca0558 | 2009-03-30 01:18:20 +0200 | [diff] [blame] | 47 | static uint8_t host_to_target_signal_table[_NSIG] = { |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 48 | [SIGHUP] = TARGET_SIGHUP, |
| 49 | [SIGINT] = TARGET_SIGINT, |
| 50 | [SIGQUIT] = TARGET_SIGQUIT, |
| 51 | [SIGILL] = TARGET_SIGILL, |
| 52 | [SIGTRAP] = TARGET_SIGTRAP, |
| 53 | [SIGABRT] = TARGET_SIGABRT, |
bellard | 01e3b76 | 2003-09-30 21:10:14 +0000 | [diff] [blame] | 54 | /* [SIGIOT] = TARGET_SIGIOT,*/ |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 55 | [SIGBUS] = TARGET_SIGBUS, |
| 56 | [SIGFPE] = TARGET_SIGFPE, |
| 57 | [SIGKILL] = TARGET_SIGKILL, |
| 58 | [SIGUSR1] = TARGET_SIGUSR1, |
| 59 | [SIGSEGV] = TARGET_SIGSEGV, |
| 60 | [SIGUSR2] = TARGET_SIGUSR2, |
| 61 | [SIGPIPE] = TARGET_SIGPIPE, |
| 62 | [SIGALRM] = TARGET_SIGALRM, |
| 63 | [SIGTERM] = TARGET_SIGTERM, |
| 64 | #ifdef SIGSTKFLT |
| 65 | [SIGSTKFLT] = TARGET_SIGSTKFLT, |
| 66 | #endif |
| 67 | [SIGCHLD] = TARGET_SIGCHLD, |
| 68 | [SIGCONT] = TARGET_SIGCONT, |
| 69 | [SIGSTOP] = TARGET_SIGSTOP, |
| 70 | [SIGTSTP] = TARGET_SIGTSTP, |
| 71 | [SIGTTIN] = TARGET_SIGTTIN, |
| 72 | [SIGTTOU] = TARGET_SIGTTOU, |
| 73 | [SIGURG] = TARGET_SIGURG, |
| 74 | [SIGXCPU] = TARGET_SIGXCPU, |
| 75 | [SIGXFSZ] = TARGET_SIGXFSZ, |
| 76 | [SIGVTALRM] = TARGET_SIGVTALRM, |
| 77 | [SIGPROF] = TARGET_SIGPROF, |
| 78 | [SIGWINCH] = TARGET_SIGWINCH, |
| 79 | [SIGIO] = TARGET_SIGIO, |
| 80 | [SIGPWR] = TARGET_SIGPWR, |
| 81 | [SIGSYS] = TARGET_SIGSYS, |
| 82 | /* next signals stay the same */ |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 83 | /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with |
Dong Xu Wang | b4916d7 | 2011-11-22 18:06:17 +0800 | [diff] [blame] | 84 | host libpthread signals. This assumes no one actually uses SIGRTMAX :-/ |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 85 | To fix this properly we need to do manual signal delivery multiplexed |
| 86 | over a single host signal. */ |
| 87 | [__SIGRTMIN] = __SIGRTMAX, |
| 88 | [__SIGRTMAX] = __SIGRTMIN, |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 89 | }; |
Arnaud Patard | 3ca0558 | 2009-03-30 01:18:20 +0200 | [diff] [blame] | 90 | static uint8_t target_to_host_signal_table[_NSIG]; |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 91 | |
pbrook | 1d9d8b5 | 2009-04-16 15:17:02 +0000 | [diff] [blame] | 92 | int host_to_target_signal(int sig) |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 93 | { |
Arnaud Patard | 3ca0558 | 2009-03-30 01:18:20 +0200 | [diff] [blame] | 94 | if (sig >= _NSIG) |
pbrook | 4cb0596 | 2008-05-30 18:05:19 +0000 | [diff] [blame] | 95 | return sig; |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 96 | return host_to_target_signal_table[sig]; |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 97 | } |
| 98 | |
pbrook | 4cb0596 | 2008-05-30 18:05:19 +0000 | [diff] [blame] | 99 | int target_to_host_signal(int sig) |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 100 | { |
Arnaud Patard | 3ca0558 | 2009-03-30 01:18:20 +0200 | [diff] [blame] | 101 | if (sig >= _NSIG) |
pbrook | 4cb0596 | 2008-05-30 18:05:19 +0000 | [diff] [blame] | 102 | return sig; |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 103 | return target_to_host_signal_table[sig]; |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 104 | } |
| 105 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 106 | static inline void target_sigaddset(target_sigset_t *set, int signum) |
pbrook | f5545b5 | 2008-05-30 22:37:07 +0000 | [diff] [blame] | 107 | { |
| 108 | signum--; |
| 109 | abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW); |
| 110 | set->sig[signum / TARGET_NSIG_BPW] |= mask; |
| 111 | } |
| 112 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 113 | static inline int target_sigismember(const target_sigset_t *set, int signum) |
pbrook | f5545b5 | 2008-05-30 22:37:07 +0000 | [diff] [blame] | 114 | { |
| 115 | signum--; |
| 116 | abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW); |
| 117 | return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0); |
| 118 | } |
| 119 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 120 | static void host_to_target_sigset_internal(target_sigset_t *d, |
bellard | 9231944 | 2004-06-19 16:58:13 +0000 | [diff] [blame] | 121 | const sigset_t *s) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 122 | { |
| 123 | int i; |
pbrook | f5545b5 | 2008-05-30 22:37:07 +0000 | [diff] [blame] | 124 | target_sigemptyset(d); |
| 125 | for (i = 1; i <= TARGET_NSIG; i++) { |
| 126 | if (sigismember(s, i)) { |
| 127 | target_sigaddset(d, host_to_target_signal(i)); |
| 128 | } |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 129 | } |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 130 | } |
| 131 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 132 | void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) |
bellard | 9231944 | 2004-06-19 16:58:13 +0000 | [diff] [blame] | 133 | { |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 134 | target_sigset_t d1; |
bellard | 9231944 | 2004-06-19 16:58:13 +0000 | [diff] [blame] | 135 | int i; |
| 136 | |
| 137 | host_to_target_sigset_internal(&d1, s); |
| 138 | for(i = 0;i < TARGET_NSIG_WORDS; i++) |
Matthias Braun | cbb21ee | 2011-08-12 19:57:41 +0200 | [diff] [blame] | 139 | d->sig[i] = tswapal(d1.sig[i]); |
bellard | 9231944 | 2004-06-19 16:58:13 +0000 | [diff] [blame] | 140 | } |
| 141 | |
Peter Maydell | da30d85 | 2011-12-05 19:42:18 +0000 | [diff] [blame] | 142 | void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 143 | { |
| 144 | int i; |
pbrook | f5545b5 | 2008-05-30 22:37:07 +0000 | [diff] [blame] | 145 | sigemptyset(d); |
| 146 | for (i = 1; i <= TARGET_NSIG; i++) { |
| 147 | if (target_sigismember(s, i)) { |
| 148 | sigaddset(d, target_to_host_signal(i)); |
| 149 | } |
| 150 | } |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 151 | } |
| 152 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 153 | void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) |
bellard | 9231944 | 2004-06-19 16:58:13 +0000 | [diff] [blame] | 154 | { |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 155 | target_sigset_t s1; |
bellard | 9231944 | 2004-06-19 16:58:13 +0000 | [diff] [blame] | 156 | int i; |
| 157 | |
| 158 | for(i = 0;i < TARGET_NSIG_WORDS; i++) |
Matthias Braun | cbb21ee | 2011-08-12 19:57:41 +0200 | [diff] [blame] | 159 | s1.sig[i] = tswapal(s->sig[i]); |
bellard | 9231944 | 2004-06-19 16:58:13 +0000 | [diff] [blame] | 160 | target_to_host_sigset_internal(d, &s1); |
| 161 | } |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 162 | |
blueswir1 | 992f48a | 2007-10-14 16:27:31 +0000 | [diff] [blame] | 163 | void host_to_target_old_sigset(abi_ulong *old_sigset, |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 164 | const sigset_t *sigset) |
| 165 | { |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 166 | target_sigset_t d; |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 167 | host_to_target_sigset(&d, sigset); |
| 168 | *old_sigset = d.sig[0]; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 169 | } |
| 170 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 171 | void target_to_host_old_sigset(sigset_t *sigset, |
blueswir1 | 992f48a | 2007-10-14 16:27:31 +0000 | [diff] [blame] | 172 | const abi_ulong *old_sigset) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 173 | { |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 174 | target_sigset_t d; |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 175 | int i; |
| 176 | |
| 177 | d.sig[0] = *old_sigset; |
| 178 | for(i = 1;i < TARGET_NSIG_WORDS; i++) |
| 179 | d.sig[i] = 0; |
| 180 | target_to_host_sigset(sigset, &d); |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 181 | } |
| 182 | |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 183 | /* siginfo conversion */ |
| 184 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 185 | static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 186 | const siginfo_t *info) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 187 | { |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 188 | int sig; |
| 189 | sig = host_to_target_signal(info->si_signo); |
| 190 | tinfo->si_signo = sig; |
| 191 | tinfo->si_errno = 0; |
pbrook | afd7cd9 | 2008-05-31 12:14:21 +0000 | [diff] [blame] | 192 | tinfo->si_code = info->si_code; |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 193 | if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || |
bellard | 447db21 | 2003-05-10 15:10:36 +0000 | [diff] [blame] | 194 | sig == SIGBUS || sig == SIGTRAP) { |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 195 | /* should never come here, but who knows. The information for |
| 196 | the target is irrelevant */ |
| 197 | tinfo->_sifields._sigfault._addr = 0; |
ths | 7f7f7c8 | 2007-07-12 11:02:46 +0000 | [diff] [blame] | 198 | } else if (sig == SIGIO) { |
| 199 | tinfo->_sifields._sigpoll._fd = info->si_fd; |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 200 | } else if (sig >= TARGET_SIGRTMIN) { |
| 201 | tinfo->_sifields._rt._pid = info->si_pid; |
| 202 | tinfo->_sifields._rt._uid = info->si_uid; |
| 203 | /* XXX: potential problem if 64 bit */ |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 204 | tinfo->_sifields._rt._sigval.sival_ptr = |
bellard | 459a401 | 2007-11-11 19:45:10 +0000 | [diff] [blame] | 205 | (abi_ulong)(unsigned long)info->si_value.sival_ptr; |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 206 | } |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 207 | } |
| 208 | |
Peter Maydell | da30d85 | 2011-12-05 19:42:18 +0000 | [diff] [blame] | 209 | void tswap_siginfo(target_siginfo_t *tinfo, |
| 210 | const target_siginfo_t *info) |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 211 | { |
| 212 | int sig; |
| 213 | sig = info->si_signo; |
| 214 | tinfo->si_signo = tswap32(sig); |
| 215 | tinfo->si_errno = tswap32(info->si_errno); |
| 216 | tinfo->si_code = tswap32(info->si_code); |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 217 | if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || |
bellard | 447db21 | 2003-05-10 15:10:36 +0000 | [diff] [blame] | 218 | sig == SIGBUS || sig == SIGTRAP) { |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 219 | tinfo->_sifields._sigfault._addr = |
Matthias Braun | cbb21ee | 2011-08-12 19:57:41 +0200 | [diff] [blame] | 220 | tswapal(info->_sifields._sigfault._addr); |
ths | 7f7f7c8 | 2007-07-12 11:02:46 +0000 | [diff] [blame] | 221 | } else if (sig == SIGIO) { |
| 222 | tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd); |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 223 | } else if (sig >= TARGET_SIGRTMIN) { |
| 224 | tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid); |
| 225 | tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid); |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 226 | tinfo->_sifields._rt._sigval.sival_ptr = |
Matthias Braun | cbb21ee | 2011-08-12 19:57:41 +0200 | [diff] [blame] | 227 | tswapal(info->_sifields._rt._sigval.sival_ptr); |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 228 | } |
| 229 | } |
| 230 | |
| 231 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 232 | void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 233 | { |
| 234 | host_to_target_siginfo_noswap(tinfo, info); |
| 235 | tswap_siginfo(tinfo, tinfo); |
| 236 | } |
| 237 | |
| 238 | /* XXX: we support only POSIX RT signals are used. */ |
ths | aa1f17c | 2007-07-11 22:48:58 +0000 | [diff] [blame] | 239 | /* XXX: find a solution for 64 bit (additional malloced data is needed) */ |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 240 | void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 241 | { |
| 242 | info->si_signo = tswap32(tinfo->si_signo); |
| 243 | info->si_errno = tswap32(tinfo->si_errno); |
| 244 | info->si_code = tswap32(tinfo->si_code); |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 245 | info->si_pid = tswap32(tinfo->_sifields._rt._pid); |
| 246 | info->si_uid = tswap32(tinfo->_sifields._rt._uid); |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 247 | info->si_value.sival_ptr = |
Matthias Braun | cbb21ee | 2011-08-12 19:57:41 +0200 | [diff] [blame] | 248 | (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr); |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 249 | } |
| 250 | |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 251 | static int fatal_signal (int sig) |
| 252 | { |
| 253 | switch (sig) { |
| 254 | case TARGET_SIGCHLD: |
| 255 | case TARGET_SIGURG: |
| 256 | case TARGET_SIGWINCH: |
| 257 | /* Ignored by default. */ |
| 258 | return 0; |
| 259 | case TARGET_SIGCONT: |
| 260 | case TARGET_SIGSTOP: |
| 261 | case TARGET_SIGTSTP: |
| 262 | case TARGET_SIGTTIN: |
| 263 | case TARGET_SIGTTOU: |
| 264 | /* Job control signals. */ |
| 265 | return 0; |
| 266 | default: |
| 267 | return 1; |
| 268 | } |
| 269 | } |
| 270 | |
Mika Westerberg | edf8e2a | 2009-04-07 09:57:11 +0300 | [diff] [blame] | 271 | /* returns 1 if given signal should dump core if not handled */ |
| 272 | static int core_dump_signal(int sig) |
| 273 | { |
| 274 | switch (sig) { |
| 275 | case TARGET_SIGABRT: |
| 276 | case TARGET_SIGFPE: |
| 277 | case TARGET_SIGILL: |
| 278 | case TARGET_SIGQUIT: |
| 279 | case TARGET_SIGSEGV: |
| 280 | case TARGET_SIGTRAP: |
| 281 | case TARGET_SIGBUS: |
| 282 | return (1); |
| 283 | default: |
| 284 | return (0); |
| 285 | } |
| 286 | } |
| 287 | |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 288 | void signal_init(void) |
| 289 | { |
| 290 | struct sigaction act; |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 291 | struct sigaction oact; |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 292 | int i, j; |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 293 | int host_sig; |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 294 | |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 295 | /* generate signal conversion tables */ |
Arnaud Patard | 3ca0558 | 2009-03-30 01:18:20 +0200 | [diff] [blame] | 296 | for(i = 1; i < _NSIG; i++) { |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 297 | if (host_to_target_signal_table[i] == 0) |
| 298 | host_to_target_signal_table[i] = i; |
| 299 | } |
Arnaud Patard | 3ca0558 | 2009-03-30 01:18:20 +0200 | [diff] [blame] | 300 | for(i = 1; i < _NSIG; i++) { |
bellard | 9e5f528 | 2003-07-13 17:33:54 +0000 | [diff] [blame] | 301 | j = host_to_target_signal_table[i]; |
| 302 | target_to_host_signal_table[j] = i; |
| 303 | } |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 304 | |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 305 | /* set all host signal handlers. ALL signals are blocked during |
| 306 | the handlers to serialize them. */ |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 307 | memset(sigact_table, 0, sizeof(sigact_table)); |
| 308 | |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 309 | sigfillset(&act.sa_mask); |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 310 | act.sa_flags = SA_SIGINFO; |
| 311 | act.sa_sigaction = host_signal_handler; |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 312 | for(i = 1; i <= TARGET_NSIG; i++) { |
| 313 | host_sig = target_to_host_signal(i); |
| 314 | sigaction(host_sig, NULL, &oact); |
| 315 | if (oact.sa_sigaction == (void *)SIG_IGN) { |
| 316 | sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN; |
| 317 | } else if (oact.sa_sigaction == (void *)SIG_DFL) { |
| 318 | sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL; |
| 319 | } |
| 320 | /* If there's already a handler installed then something has |
| 321 | gone horribly wrong, so don't even try to handle that case. */ |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 322 | /* Install some handlers for our own use. We need at least |
| 323 | SIGSEGV and SIGBUS, to detect exceptions. We can not just |
| 324 | trap all signals because it affects syscall interrupt |
| 325 | behavior. But do trap all default-fatal signals. */ |
| 326 | if (fatal_signal (i)) |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 327 | sigaction(host_sig, &act, NULL); |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 328 | } |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 329 | } |
| 330 | |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 331 | /* signal queue handling */ |
| 332 | |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 333 | static inline struct sigqueue *alloc_sigqueue(CPUState *env) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 334 | { |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 335 | TaskState *ts = env->opaque; |
| 336 | struct sigqueue *q = ts->first_free; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 337 | if (!q) |
| 338 | return NULL; |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 339 | ts->first_free = q->next; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 340 | return q; |
| 341 | } |
| 342 | |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 343 | static inline void free_sigqueue(CPUState *env, struct sigqueue *q) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 344 | { |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 345 | TaskState *ts = env->opaque; |
| 346 | q->next = ts->first_free; |
| 347 | ts->first_free = q; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 348 | } |
| 349 | |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 350 | /* abort execution with signal */ |
Peter Maydell | da30d85 | 2011-12-05 19:42:18 +0000 | [diff] [blame] | 351 | void QEMU_NORETURN force_sig(int target_sig) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 352 | { |
Mika Westerberg | edf8e2a | 2009-04-07 09:57:11 +0300 | [diff] [blame] | 353 | TaskState *ts = (TaskState *)thread_env->opaque; |
| 354 | int host_sig, core_dumped = 0; |
aurel32 | 603e4fd | 2009-04-15 16:18:38 +0000 | [diff] [blame] | 355 | struct sigaction act; |
Riku Voipio | 66393fb | 2009-12-04 15:16:32 +0200 | [diff] [blame] | 356 | host_sig = target_to_host_signal(target_sig); |
| 357 | gdb_signalled(thread_env, target_sig); |
aurel32 | 603e4fd | 2009-04-15 16:18:38 +0000 | [diff] [blame] | 358 | |
Mika Westerberg | edf8e2a | 2009-04-07 09:57:11 +0300 | [diff] [blame] | 359 | /* dump core if supported by target binary format */ |
Riku Voipio | 66393fb | 2009-12-04 15:16:32 +0200 | [diff] [blame] | 360 | if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) { |
Mika Westerberg | edf8e2a | 2009-04-07 09:57:11 +0300 | [diff] [blame] | 361 | stop_all_tasks(); |
| 362 | core_dumped = |
Riku Voipio | 66393fb | 2009-12-04 15:16:32 +0200 | [diff] [blame] | 363 | ((*ts->bprm->core_dump)(target_sig, thread_env) == 0); |
Mika Westerberg | edf8e2a | 2009-04-07 09:57:11 +0300 | [diff] [blame] | 364 | } |
| 365 | if (core_dumped) { |
| 366 | /* we already dumped the core of target process, we don't want |
| 367 | * a coredump of qemu itself */ |
| 368 | struct rlimit nodump; |
| 369 | getrlimit(RLIMIT_CORE, &nodump); |
| 370 | nodump.rlim_cur=0; |
| 371 | setrlimit(RLIMIT_CORE, &nodump); |
| 372 | (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n", |
Riku Voipio | 66393fb | 2009-12-04 15:16:32 +0200 | [diff] [blame] | 373 | target_sig, strsignal(host_sig), "core dumped" ); |
Mika Westerberg | edf8e2a | 2009-04-07 09:57:11 +0300 | [diff] [blame] | 374 | } |
| 375 | |
Stefan Weil | 0c58751 | 2011-04-28 17:20:32 +0200 | [diff] [blame] | 376 | /* The proper exit code for dying from an uncaught signal is |
aurel32 | 603e4fd | 2009-04-15 16:18:38 +0000 | [diff] [blame] | 377 | * -<signal>. The kernel doesn't allow exit() or _exit() to pass |
| 378 | * a negative value. To get the proper exit code we need to |
| 379 | * actually die from an uncaught signal. Here the default signal |
| 380 | * handler is installed, we send ourself a signal and we wait for |
| 381 | * it to arrive. */ |
| 382 | sigfillset(&act.sa_mask); |
| 383 | act.sa_handler = SIG_DFL; |
| 384 | sigaction(host_sig, &act, NULL); |
| 385 | |
| 386 | /* For some reason raise(host_sig) doesn't send the signal when |
| 387 | * statically linked on x86-64. */ |
| 388 | kill(getpid(), host_sig); |
| 389 | |
| 390 | /* Make sure the signal isn't masked (just reuse the mask inside |
| 391 | of act) */ |
| 392 | sigdelset(&act.sa_mask, host_sig); |
| 393 | sigsuspend(&act.sa_mask); |
| 394 | |
| 395 | /* unreachable */ |
Blue Swirl | a6c6f76 | 2010-03-13 14:18:50 +0000 | [diff] [blame] | 396 | abort(); |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 397 | } |
| 398 | |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 399 | /* queue a signal so that it will be send to the virtual CPU as soon |
| 400 | as possible */ |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 401 | int queue_signal(CPUState *env, int sig, target_siginfo_t *info) |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 402 | { |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 403 | TaskState *ts = env->opaque; |
| 404 | struct emulated_sigtable *k; |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 405 | struct sigqueue *q, **pq; |
blueswir1 | 992f48a | 2007-10-14 16:27:31 +0000 | [diff] [blame] | 406 | abi_ulong handler; |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 407 | int queue; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 408 | |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 409 | #if defined(DEBUG_SIGNAL) |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 410 | fprintf(stderr, "queue_signal: sig=%d\n", |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 411 | sig); |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 412 | #endif |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 413 | k = &ts->sigtab[sig - 1]; |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 414 | queue = gdb_queuesig (); |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 415 | handler = sigact_table[sig - 1]._sa_handler; |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 416 | if (!queue && handler == TARGET_SIG_DFL) { |
ths | 60b1969 | 2008-11-27 15:47:15 +0000 | [diff] [blame] | 417 | if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) { |
| 418 | kill(getpid(),SIGSTOP); |
| 419 | return 0; |
| 420 | } else |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 421 | /* default handler : ignore some signal. The other are fatal */ |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 422 | if (sig != TARGET_SIGCHLD && |
| 423 | sig != TARGET_SIGURG && |
ths | 60b1969 | 2008-11-27 15:47:15 +0000 | [diff] [blame] | 424 | sig != TARGET_SIGWINCH && |
| 425 | sig != TARGET_SIGCONT) { |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 426 | force_sig(sig); |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 427 | } else { |
| 428 | return 0; /* indicate ignored */ |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 429 | } |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 430 | } else if (!queue && handler == TARGET_SIG_IGN) { |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 431 | /* ignore signal */ |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 432 | return 0; |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 433 | } else if (!queue && handler == TARGET_SIG_ERR) { |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 434 | force_sig(sig); |
| 435 | } else { |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 436 | pq = &k->first; |
| 437 | if (sig < TARGET_SIGRTMIN) { |
| 438 | /* if non real time signal, we queue exactly one signal */ |
| 439 | if (!k->pending) |
| 440 | q = &k->info; |
| 441 | else |
| 442 | return 0; |
| 443 | } else { |
| 444 | if (!k->pending) { |
| 445 | /* first signal */ |
| 446 | q = &k->info; |
| 447 | } else { |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 448 | q = alloc_sigqueue(env); |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 449 | if (!q) |
| 450 | return -EAGAIN; |
| 451 | while (*pq != NULL) |
| 452 | pq = &(*pq)->next; |
| 453 | } |
| 454 | } |
| 455 | *pq = q; |
| 456 | q->info = *info; |
| 457 | q->next = NULL; |
| 458 | k->pending = 1; |
| 459 | /* signal that a new signal is pending */ |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 460 | ts->signal_pending = 1; |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 461 | return 1; /* indicates that the signal was queued */ |
| 462 | } |
| 463 | } |
| 464 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 465 | static void host_signal_handler(int host_signum, siginfo_t *info, |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 466 | void *puc) |
| 467 | { |
| 468 | int sig; |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 469 | target_siginfo_t tinfo; |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 470 | |
| 471 | /* the CPU emulator uses some host signals to detect exceptions, |
aurel32 | eaa449b | 2009-01-03 13:14:52 +0000 | [diff] [blame] | 472 | we forward to it some signals */ |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 473 | if ((host_signum == SIGSEGV || host_signum == SIGBUS) |
aurel32 | eaa449b | 2009-01-03 13:14:52 +0000 | [diff] [blame] | 474 | && info->si_code > 0) { |
bellard | b346ff4 | 2003-06-15 20:05:50 +0000 | [diff] [blame] | 475 | if (cpu_signal_handler(host_signum, info, puc)) |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 476 | return; |
| 477 | } |
| 478 | |
| 479 | /* get target signal number */ |
| 480 | sig = host_to_target_signal(host_signum); |
| 481 | if (sig < 1 || sig > TARGET_NSIG) |
| 482 | return; |
| 483 | #if defined(DEBUG_SIGNAL) |
bellard | bc8a22c | 2003-03-30 21:02:40 +0000 | [diff] [blame] | 484 | fprintf(stderr, "qemu: got signal %d\n", sig); |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 485 | #endif |
| 486 | host_to_target_siginfo_noswap(&tinfo, info); |
pbrook | d597536 | 2008-06-07 20:50:51 +0000 | [diff] [blame] | 487 | if (queue_signal(thread_env, sig, &tinfo) == 1) { |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 488 | /* interrupt the virtual CPU as soon as possible */ |
aurel32 | 3098dba | 2009-03-07 21:28:24 +0000 | [diff] [blame] | 489 | cpu_exit(thread_env); |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 490 | } |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 491 | } |
| 492 | |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 493 | /* do_sigaltstack() returns target values and errnos. */ |
bellard | 579a97f | 2007-11-11 14:26:47 +0000 | [diff] [blame] | 494 | /* compare linux/kernel/signal.c:do_sigaltstack() */ |
| 495 | abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 496 | { |
| 497 | int ret; |
| 498 | struct target_sigaltstack oss; |
| 499 | |
| 500 | /* XXX: test errors */ |
bellard | 579a97f | 2007-11-11 14:26:47 +0000 | [diff] [blame] | 501 | if(uoss_addr) |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 502 | { |
| 503 | __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp); |
| 504 | __put_user(target_sigaltstack_used.ss_size, &oss.ss_size); |
| 505 | __put_user(sas_ss_flags(sp), &oss.ss_flags); |
| 506 | } |
| 507 | |
bellard | 579a97f | 2007-11-11 14:26:47 +0000 | [diff] [blame] | 508 | if(uss_addr) |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 509 | { |
bellard | 579a97f | 2007-11-11 14:26:47 +0000 | [diff] [blame] | 510 | struct target_sigaltstack *uss; |
| 511 | struct target_sigaltstack ss; |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 512 | |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 513 | ret = -TARGET_EFAULT; |
bellard | 579a97f | 2007-11-11 14:26:47 +0000 | [diff] [blame] | 514 | if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 515 | || __get_user(ss.ss_sp, &uss->ss_sp) |
| 516 | || __get_user(ss.ss_size, &uss->ss_size) |
| 517 | || __get_user(ss.ss_flags, &uss->ss_flags)) |
| 518 | goto out; |
bellard | 579a97f | 2007-11-11 14:26:47 +0000 | [diff] [blame] | 519 | unlock_user_struct(uss, uss_addr, 0); |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 520 | |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 521 | ret = -TARGET_EPERM; |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 522 | if (on_sig_stack(sp)) |
| 523 | goto out; |
| 524 | |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 525 | ret = -TARGET_EINVAL; |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 526 | if (ss.ss_flags != TARGET_SS_DISABLE |
| 527 | && ss.ss_flags != TARGET_SS_ONSTACK |
| 528 | && ss.ss_flags != 0) |
| 529 | goto out; |
| 530 | |
| 531 | if (ss.ss_flags == TARGET_SS_DISABLE) { |
| 532 | ss.ss_size = 0; |
| 533 | ss.ss_sp = 0; |
| 534 | } else { |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 535 | ret = -TARGET_ENOMEM; |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 536 | if (ss.ss_size < MINSIGSTKSZ) |
| 537 | goto out; |
| 538 | } |
| 539 | |
| 540 | target_sigaltstack_used.ss_sp = ss.ss_sp; |
| 541 | target_sigaltstack_used.ss_size = ss.ss_size; |
| 542 | } |
| 543 | |
bellard | 579a97f | 2007-11-11 14:26:47 +0000 | [diff] [blame] | 544 | if (uoss_addr) { |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 545 | ret = -TARGET_EFAULT; |
bellard | 579a97f | 2007-11-11 14:26:47 +0000 | [diff] [blame] | 546 | if (copy_to_user(uoss_addr, &oss, sizeof(oss))) |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 547 | goto out; |
ths | a04e134 | 2007-09-27 13:57:58 +0000 | [diff] [blame] | 548 | } |
| 549 | |
| 550 | ret = 0; |
| 551 | out: |
| 552 | return ret; |
| 553 | } |
| 554 | |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 555 | /* do_sigaction() return host values and errnos */ |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 556 | int do_sigaction(int sig, const struct target_sigaction *act, |
| 557 | struct target_sigaction *oact) |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 558 | { |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 559 | struct target_sigaction *k; |
bellard | 773b93e | 2004-01-04 17:15:59 +0000 | [diff] [blame] | 560 | struct sigaction act1; |
| 561 | int host_sig; |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 562 | int ret = 0; |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 563 | |
ths | 2a913eb | 2008-11-27 15:46:25 +0000 | [diff] [blame] | 564 | if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 565 | return -EINVAL; |
| 566 | k = &sigact_table[sig - 1]; |
bellard | 773b93e | 2004-01-04 17:15:59 +0000 | [diff] [blame] | 567 | #if defined(DEBUG_SIGNAL) |
Blue Swirl | 0bf9e31 | 2009-07-20 17:19:25 +0000 | [diff] [blame] | 568 | fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n", |
| 569 | sig, act, oact); |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 570 | #endif |
| 571 | if (oact) { |
Matthias Braun | cbb21ee | 2011-08-12 19:57:41 +0200 | [diff] [blame] | 572 | oact->_sa_handler = tswapal(k->_sa_handler); |
| 573 | oact->sa_flags = tswapal(k->sa_flags); |
ths | 388bb21 | 2007-05-13 13:58:00 +0000 | [diff] [blame] | 574 | #if !defined(TARGET_MIPS) |
Matthias Braun | cbb21ee | 2011-08-12 19:57:41 +0200 | [diff] [blame] | 575 | oact->sa_restorer = tswapal(k->sa_restorer); |
ths | 388bb21 | 2007-05-13 13:58:00 +0000 | [diff] [blame] | 576 | #endif |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 577 | oact->sa_mask = k->sa_mask; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 578 | } |
| 579 | if (act) { |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 580 | /* FIXME: This is not threadsafe. */ |
Matthias Braun | cbb21ee | 2011-08-12 19:57:41 +0200 | [diff] [blame] | 581 | k->_sa_handler = tswapal(act->_sa_handler); |
| 582 | k->sa_flags = tswapal(act->sa_flags); |
ths | 388bb21 | 2007-05-13 13:58:00 +0000 | [diff] [blame] | 583 | #if !defined(TARGET_MIPS) |
Matthias Braun | cbb21ee | 2011-08-12 19:57:41 +0200 | [diff] [blame] | 584 | k->sa_restorer = tswapal(act->sa_restorer); |
ths | 388bb21 | 2007-05-13 13:58:00 +0000 | [diff] [blame] | 585 | #endif |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 586 | k->sa_mask = act->sa_mask; |
bellard | 773b93e | 2004-01-04 17:15:59 +0000 | [diff] [blame] | 587 | |
| 588 | /* we update the host linux signal state */ |
| 589 | host_sig = target_to_host_signal(sig); |
| 590 | if (host_sig != SIGSEGV && host_sig != SIGBUS) { |
| 591 | sigfillset(&act1.sa_mask); |
| 592 | act1.sa_flags = SA_SIGINFO; |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 593 | if (k->sa_flags & TARGET_SA_RESTART) |
bellard | 773b93e | 2004-01-04 17:15:59 +0000 | [diff] [blame] | 594 | act1.sa_flags |= SA_RESTART; |
| 595 | /* NOTE: it is important to update the host kernel signal |
| 596 | ignore state to avoid getting unexpected interrupted |
| 597 | syscalls */ |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 598 | if (k->_sa_handler == TARGET_SIG_IGN) { |
bellard | 773b93e | 2004-01-04 17:15:59 +0000 | [diff] [blame] | 599 | act1.sa_sigaction = (void *)SIG_IGN; |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 600 | } else if (k->_sa_handler == TARGET_SIG_DFL) { |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 601 | if (fatal_signal (sig)) |
| 602 | act1.sa_sigaction = host_signal_handler; |
| 603 | else |
| 604 | act1.sa_sigaction = (void *)SIG_DFL; |
bellard | 773b93e | 2004-01-04 17:15:59 +0000 | [diff] [blame] | 605 | } else { |
| 606 | act1.sa_sigaction = host_signal_handler; |
| 607 | } |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 608 | ret = sigaction(host_sig, &act1, NULL); |
bellard | 773b93e | 2004-01-04 17:15:59 +0000 | [diff] [blame] | 609 | } |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 610 | } |
ths | 0da46a6 | 2007-10-20 20:23:07 +0000 | [diff] [blame] | 611 | return ret; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 612 | } |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 613 | |
bellard | b346ff4 | 2003-06-15 20:05:50 +0000 | [diff] [blame] | 614 | |
bellard | b346ff4 | 2003-06-15 20:05:50 +0000 | [diff] [blame] | 615 | |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 616 | |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 617 | void process_pending_signals(CPUState *cpu_env) |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 618 | { |
| 619 | int sig; |
blueswir1 | 992f48a | 2007-10-14 16:27:31 +0000 | [diff] [blame] | 620 | abi_ulong handler; |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 621 | sigset_t set, old_set; |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 622 | target_sigset_t target_old_set; |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 623 | struct emulated_sigtable *k; |
| 624 | struct target_sigaction *sa; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 625 | struct sigqueue *q; |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 626 | TaskState *ts = cpu_env->opaque; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 627 | |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 628 | if (!ts->signal_pending) |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 629 | return; |
| 630 | |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 631 | /* FIXME: This is not threadsafe. */ |
| 632 | k = ts->sigtab; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 633 | for(sig = 1; sig <= TARGET_NSIG; sig++) { |
| 634 | if (k->pending) |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 635 | goto handle_signal; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 636 | k++; |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 637 | } |
| 638 | /* if no signal is pending, just return */ |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 639 | ts->signal_pending = 0; |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 640 | return; |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 641 | |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 642 | handle_signal: |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 643 | #ifdef DEBUG_SIGNAL |
bellard | bc8a22c | 2003-03-30 21:02:40 +0000 | [diff] [blame] | 644 | fprintf(stderr, "qemu: process signal %d\n", sig); |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 645 | #endif |
| 646 | /* dequeue signal */ |
| 647 | q = k->first; |
| 648 | k->first = q->next; |
| 649 | if (!k->first) |
| 650 | k->pending = 0; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 651 | |
bellard | 1fddef4 | 2005-04-17 19:16:13 +0000 | [diff] [blame] | 652 | sig = gdb_handlesig (cpu_env, sig); |
| 653 | if (!sig) { |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 654 | sa = NULL; |
| 655 | handler = TARGET_SIG_IGN; |
| 656 | } else { |
| 657 | sa = &sigact_table[sig - 1]; |
| 658 | handler = sa->_sa_handler; |
bellard | 1fddef4 | 2005-04-17 19:16:13 +0000 | [diff] [blame] | 659 | } |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 660 | |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 661 | if (handler == TARGET_SIG_DFL) { |
aurel32 | ca587a8 | 2008-12-18 22:44:13 +0000 | [diff] [blame] | 662 | /* default handler : ignore some signal. The other are job control or fatal */ |
| 663 | if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) { |
| 664 | kill(getpid(),SIGSTOP); |
| 665 | } else if (sig != TARGET_SIGCHLD && |
| 666 | sig != TARGET_SIGURG && |
| 667 | sig != TARGET_SIGWINCH && |
| 668 | sig != TARGET_SIGCONT) { |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 669 | force_sig(sig); |
| 670 | } |
| 671 | } else if (handler == TARGET_SIG_IGN) { |
| 672 | /* ignore sig */ |
| 673 | } else if (handler == TARGET_SIG_ERR) { |
| 674 | force_sig(sig); |
| 675 | } else { |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 676 | /* compute the blocked signals during the handler execution */ |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 677 | target_to_host_sigset(&set, &sa->sa_mask); |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 678 | /* SA_NODEFER indicates that the current signal should not be |
| 679 | blocked during the handler */ |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 680 | if (!(sa->sa_flags & TARGET_SA_NODEFER)) |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 681 | sigaddset(&set, target_to_host_signal(sig)); |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 682 | |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 683 | /* block signals in the handler using Linux */ |
| 684 | sigprocmask(SIG_BLOCK, &set, &old_set); |
| 685 | /* save the previous blocked signal state to restore it at the |
| 686 | end of the signal execution (see do_sigreturn) */ |
bellard | 9231944 | 2004-06-19 16:58:13 +0000 | [diff] [blame] | 687 | host_to_target_sigset_internal(&target_old_set, &old_set); |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 688 | |
bellard | bc8a22c | 2003-03-30 21:02:40 +0000 | [diff] [blame] | 689 | /* if the CPU is in VM86 mode, we restore the 32 bit values */ |
j_mayer | 84409dd | 2007-04-06 08:56:50 +0000 | [diff] [blame] | 690 | #if defined(TARGET_I386) && !defined(TARGET_X86_64) |
bellard | bc8a22c | 2003-03-30 21:02:40 +0000 | [diff] [blame] | 691 | { |
| 692 | CPUX86State *env = cpu_env; |
| 693 | if (env->eflags & VM_MASK) |
| 694 | save_v86_state(env); |
| 695 | } |
| 696 | #endif |
bellard | 9de5e44 | 2003-03-23 16:49:39 +0000 | [diff] [blame] | 697 | /* prepare the stack frame of the virtual CPU */ |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 698 | if (sa->sa_flags & TARGET_SA_SIGINFO) |
| 699 | setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env); |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 700 | else |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 701 | setup_frame(sig, sa, &target_old_set, cpu_env); |
| 702 | if (sa->sa_flags & TARGET_SA_RESETHAND) |
| 703 | sa->_sa_handler = TARGET_SIG_DFL; |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 704 | } |
bellard | 66fb976 | 2003-03-23 01:06:05 +0000 | [diff] [blame] | 705 | if (q != &k->info) |
pbrook | 624f797 | 2008-05-31 16:11:38 +0000 | [diff] [blame] | 706 | free_sigqueue(cpu_env, q); |
bellard | 31e31b8 | 2003-02-18 22:55:36 +0000 | [diff] [blame] | 707 | } |