184778508Sblueswir1 /* 284778508Sblueswir1 * Emulation of BSD signals 384778508Sblueswir1 * 484778508Sblueswir1 * Copyright (c) 2003 - 2008 Fabrice Bellard 51366ef81SWarner Losh * Copyright (c) 2013 Stacey Son 684778508Sblueswir1 * 784778508Sblueswir1 * This program is free software; you can redistribute it and/or modify 884778508Sblueswir1 * it under the terms of the GNU General Public License as published by 984778508Sblueswir1 * the Free Software Foundation; either version 2 of the License, or 1084778508Sblueswir1 * (at your option) any later version. 1184778508Sblueswir1 * 1284778508Sblueswir1 * This program is distributed in the hope that it will be useful, 1384778508Sblueswir1 * but WITHOUT ANY WARRANTY; without even the implied warranty of 1484778508Sblueswir1 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1584778508Sblueswir1 * GNU General Public License for more details. 1684778508Sblueswir1 * 1784778508Sblueswir1 * You should have received a copy of the GNU General Public License 188167ee88SBlue Swirl * along with this program; if not, see <http://www.gnu.org/licenses/>. 1984778508Sblueswir1 */ 2084778508Sblueswir1 215abfac27SWarner Losh #include "qemu/osdep.h" 2284778508Sblueswir1 #include "qemu.h" 230ef59989SWarner Losh #include "signal-common.h" 246ddc1abeSWarner Losh #include "trace.h" 25fc9f9bddSWarner Losh #include "hw/core/tcg-cpu-ops.h" 2685fc1b5dSWarner Losh #include "host-signal.h" 2784778508Sblueswir1 285abfac27SWarner Losh /* 29835b04edSWarner Losh * Stubbed out routines until we merge signal support from bsd-user 30835b04edSWarner Losh * fork. 31835b04edSWarner Losh */ 32835b04edSWarner Losh 33149076adSWarner Losh static struct target_sigaction sigact_table[TARGET_NSIG]; 34149076adSWarner Losh static void host_signal_handler(int host_sig, siginfo_t *info, void *puc); 35149076adSWarner Losh 36835b04edSWarner Losh /* 371366ef81SWarner Losh * The BSD ABIs use the same singal numbers across all the CPU architectures, so 381366ef81SWarner Losh * (unlike Linux) these functions are just the identity mapping. This might not 391366ef81SWarner Losh * be true for XyzBSD running on AbcBSD, which doesn't currently work. 401366ef81SWarner Losh */ 411366ef81SWarner Losh int host_to_target_signal(int sig) 421366ef81SWarner Losh { 431366ef81SWarner Losh return sig; 441366ef81SWarner Losh } 451366ef81SWarner Losh 461366ef81SWarner Losh int target_to_host_signal(int sig) 471366ef81SWarner Losh { 481366ef81SWarner Losh return sig; 491366ef81SWarner Losh } 501366ef81SWarner Losh 51*c34f2aafSWarner Losh static bool has_trapno(int tsig) 52*c34f2aafSWarner Losh { 53*c34f2aafSWarner Losh return tsig == TARGET_SIGILL || 54*c34f2aafSWarner Losh tsig == TARGET_SIGFPE || 55*c34f2aafSWarner Losh tsig == TARGET_SIGSEGV || 56*c34f2aafSWarner Losh tsig == TARGET_SIGBUS || 57*c34f2aafSWarner Losh tsig == TARGET_SIGTRAP; 58*c34f2aafSWarner Losh } 59*c34f2aafSWarner Losh 60*c34f2aafSWarner Losh 61*c34f2aafSWarner Losh /* Siginfo conversion. */ 62*c34f2aafSWarner Losh 63*c34f2aafSWarner Losh /* 64*c34f2aafSWarner Losh * Populate tinfo w/o swapping based on guessing which fields are valid. 65*c34f2aafSWarner Losh */ 66*c34f2aafSWarner Losh static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, 67*c34f2aafSWarner Losh const siginfo_t *info) 68*c34f2aafSWarner Losh { 69*c34f2aafSWarner Losh int sig = host_to_target_signal(info->si_signo); 70*c34f2aafSWarner Losh int si_code = info->si_code; 71*c34f2aafSWarner Losh int si_type; 72*c34f2aafSWarner Losh 73*c34f2aafSWarner Losh /* 74*c34f2aafSWarner Losh * Make sure we that the variable portion of the target siginfo is zeroed 75*c34f2aafSWarner Losh * out so we don't leak anything into that. 76*c34f2aafSWarner Losh */ 77*c34f2aafSWarner Losh memset(&tinfo->_reason, 0, sizeof(tinfo->_reason)); 78*c34f2aafSWarner Losh 79*c34f2aafSWarner Losh /* 80*c34f2aafSWarner Losh * This is awkward, because we have to use a combination of the si_code and 81*c34f2aafSWarner Losh * si_signo to figure out which of the union's members are valid.o We 82*c34f2aafSWarner Losh * therefore make our best guess. 83*c34f2aafSWarner Losh * 84*c34f2aafSWarner Losh * Once we have made our guess, we record it in the top 16 bits of 85*c34f2aafSWarner Losh * the si_code, so that tswap_siginfo() later can use it. 86*c34f2aafSWarner Losh * tswap_siginfo() will strip these top bits out before writing 87*c34f2aafSWarner Losh * si_code to the guest (sign-extending the lower bits). 88*c34f2aafSWarner Losh */ 89*c34f2aafSWarner Losh tinfo->si_signo = sig; 90*c34f2aafSWarner Losh tinfo->si_errno = info->si_errno; 91*c34f2aafSWarner Losh tinfo->si_code = info->si_code; 92*c34f2aafSWarner Losh tinfo->si_pid = info->si_pid; 93*c34f2aafSWarner Losh tinfo->si_uid = info->si_uid; 94*c34f2aafSWarner Losh tinfo->si_status = info->si_status; 95*c34f2aafSWarner Losh tinfo->si_addr = (abi_ulong)(unsigned long)info->si_addr; 96*c34f2aafSWarner Losh /* 97*c34f2aafSWarner Losh * si_value is opaque to kernel. On all FreeBSD platforms, 98*c34f2aafSWarner Losh * sizeof(sival_ptr) >= sizeof(sival_int) so the following 99*c34f2aafSWarner Losh * always will copy the larger element. 100*c34f2aafSWarner Losh */ 101*c34f2aafSWarner Losh tinfo->si_value.sival_ptr = 102*c34f2aafSWarner Losh (abi_ulong)(unsigned long)info->si_value.sival_ptr; 103*c34f2aafSWarner Losh 104*c34f2aafSWarner Losh switch (si_code) { 105*c34f2aafSWarner Losh /* 106*c34f2aafSWarner Losh * All the SI_xxx codes that are defined here are global to 107*c34f2aafSWarner Losh * all the signals (they have values that none of the other, 108*c34f2aafSWarner Losh * more specific signal info will set). 109*c34f2aafSWarner Losh */ 110*c34f2aafSWarner Losh case SI_USER: 111*c34f2aafSWarner Losh case SI_LWP: 112*c34f2aafSWarner Losh case SI_KERNEL: 113*c34f2aafSWarner Losh case SI_QUEUE: 114*c34f2aafSWarner Losh case SI_ASYNCIO: 115*c34f2aafSWarner Losh /* 116*c34f2aafSWarner Losh * Only the fixed parts are valid (though FreeBSD doesn't always 117*c34f2aafSWarner Losh * set all the fields to non-zero values. 118*c34f2aafSWarner Losh */ 119*c34f2aafSWarner Losh si_type = QEMU_SI_NOINFO; 120*c34f2aafSWarner Losh break; 121*c34f2aafSWarner Losh case SI_TIMER: 122*c34f2aafSWarner Losh tinfo->_reason._timer._timerid = info->_reason._timer._timerid; 123*c34f2aafSWarner Losh tinfo->_reason._timer._overrun = info->_reason._timer._overrun; 124*c34f2aafSWarner Losh si_type = QEMU_SI_TIMER; 125*c34f2aafSWarner Losh break; 126*c34f2aafSWarner Losh case SI_MESGQ: 127*c34f2aafSWarner Losh tinfo->_reason._mesgq._mqd = info->_reason._mesgq._mqd; 128*c34f2aafSWarner Losh si_type = QEMU_SI_MESGQ; 129*c34f2aafSWarner Losh break; 130*c34f2aafSWarner Losh default: 131*c34f2aafSWarner Losh /* 132*c34f2aafSWarner Losh * We have to go based on the signal number now to figure out 133*c34f2aafSWarner Losh * what's valid. 134*c34f2aafSWarner Losh */ 135*c34f2aafSWarner Losh if (has_trapno(sig)) { 136*c34f2aafSWarner Losh tinfo->_reason._fault._trapno = info->_reason._fault._trapno; 137*c34f2aafSWarner Losh si_type = QEMU_SI_FAULT; 138*c34f2aafSWarner Losh } 139*c34f2aafSWarner Losh #ifdef TARGET_SIGPOLL 140*c34f2aafSWarner Losh /* 141*c34f2aafSWarner Losh * FreeBSD never had SIGPOLL, but emulates it for Linux so there's 142*c34f2aafSWarner Losh * a chance it may popup in the future. 143*c34f2aafSWarner Losh */ 144*c34f2aafSWarner Losh if (sig == TARGET_SIGPOLL) { 145*c34f2aafSWarner Losh tinfo->_reason._poll._band = info->_reason._poll._band; 146*c34f2aafSWarner Losh si_type = QEMU_SI_POLL; 147*c34f2aafSWarner Losh } 148*c34f2aafSWarner Losh #endif 149*c34f2aafSWarner Losh /* 150*c34f2aafSWarner Losh * Unsure that this can actually be generated, and our support for 151*c34f2aafSWarner Losh * capsicum is somewhere between weak and non-existant, but if we get 152*c34f2aafSWarner Losh * one, then we know what to save. 153*c34f2aafSWarner Losh */ 154*c34f2aafSWarner Losh if (sig == TARGET_SIGTRAP) { 155*c34f2aafSWarner Losh tinfo->_reason._capsicum._syscall = 156*c34f2aafSWarner Losh info->_reason._capsicum._syscall; 157*c34f2aafSWarner Losh si_type = QEMU_SI_CAPSICUM; 158*c34f2aafSWarner Losh } 159*c34f2aafSWarner Losh break; 160*c34f2aafSWarner Losh } 161*c34f2aafSWarner Losh tinfo->si_code = deposit32(si_code, 24, 8, si_type); 162*c34f2aafSWarner Losh } 163*c34f2aafSWarner Losh 1641366ef81SWarner Losh /* 1655abfac27SWarner Losh * Queue a signal so that it will be send to the virtual CPU as soon as 1665abfac27SWarner Losh * possible. 1675abfac27SWarner Losh */ 168e32a6301SWarner Losh void queue_signal(CPUArchState *env, int sig, int si_type, 169e32a6301SWarner Losh target_siginfo_t *info) 1705abfac27SWarner Losh { 1715abfac27SWarner Losh qemu_log_mask(LOG_UNIMP, "No signal queueing, dropping signal %d\n", sig); 1725abfac27SWarner Losh } 1735abfac27SWarner Losh 174149076adSWarner Losh static int fatal_signal(int sig) 175149076adSWarner Losh { 176149076adSWarner Losh 177149076adSWarner Losh switch (sig) { 178149076adSWarner Losh case TARGET_SIGCHLD: 179149076adSWarner Losh case TARGET_SIGURG: 180149076adSWarner Losh case TARGET_SIGWINCH: 181149076adSWarner Losh case TARGET_SIGINFO: 182149076adSWarner Losh /* Ignored by default. */ 183149076adSWarner Losh return 0; 184149076adSWarner Losh case TARGET_SIGCONT: 185149076adSWarner Losh case TARGET_SIGSTOP: 186149076adSWarner Losh case TARGET_SIGTSTP: 187149076adSWarner Losh case TARGET_SIGTTIN: 188149076adSWarner Losh case TARGET_SIGTTOU: 189149076adSWarner Losh /* Job control signals. */ 190149076adSWarner Losh return 0; 191149076adSWarner Losh default: 192149076adSWarner Losh return 1; 193149076adSWarner Losh } 194149076adSWarner Losh } 195149076adSWarner Losh 1960ef59989SWarner Losh /* 1970ef59989SWarner Losh * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the 1980ef59989SWarner Losh * 'force' part is handled in process_pending_signals(). 1990ef59989SWarner Losh */ 2000ef59989SWarner Losh void force_sig_fault(int sig, int code, abi_ulong addr) 2010ef59989SWarner Losh { 2020ef59989SWarner Losh CPUState *cpu = thread_cpu; 2030ef59989SWarner Losh CPUArchState *env = cpu->env_ptr; 2040ef59989SWarner Losh target_siginfo_t info = {}; 2050ef59989SWarner Losh 2060ef59989SWarner Losh info.si_signo = sig; 2070ef59989SWarner Losh info.si_errno = 0; 2080ef59989SWarner Losh info.si_code = code; 2090ef59989SWarner Losh info.si_addr = addr; 210e32a6301SWarner Losh queue_signal(env, sig, QEMU_SI_FAULT, &info); 2110ef59989SWarner Losh } 2120ef59989SWarner Losh 213149076adSWarner Losh static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) 214149076adSWarner Losh { 215149076adSWarner Losh } 216149076adSWarner Losh 21784778508Sblueswir1 void signal_init(void) 21884778508Sblueswir1 { 219149076adSWarner Losh TaskState *ts = (TaskState *)thread_cpu->opaque; 220149076adSWarner Losh struct sigaction act; 221149076adSWarner Losh struct sigaction oact; 222149076adSWarner Losh int i; 223149076adSWarner Losh int host_sig; 224149076adSWarner Losh 225149076adSWarner Losh /* Set the signal mask from the host mask. */ 226149076adSWarner Losh sigprocmask(0, 0, &ts->signal_mask); 227149076adSWarner Losh 228149076adSWarner Losh sigfillset(&act.sa_mask); 229149076adSWarner Losh act.sa_sigaction = host_signal_handler; 230149076adSWarner Losh act.sa_flags = SA_SIGINFO; 231149076adSWarner Losh 232149076adSWarner Losh for (i = 1; i <= TARGET_NSIG; i++) { 233149076adSWarner Losh #ifdef CONFIG_GPROF 234149076adSWarner Losh if (i == TARGET_SIGPROF) { 235149076adSWarner Losh continue; 236149076adSWarner Losh } 237149076adSWarner Losh #endif 238149076adSWarner Losh host_sig = target_to_host_signal(i); 239149076adSWarner Losh sigaction(host_sig, NULL, &oact); 240149076adSWarner Losh if (oact.sa_sigaction == (void *)SIG_IGN) { 241149076adSWarner Losh sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN; 242149076adSWarner Losh } else if (oact.sa_sigaction == (void *)SIG_DFL) { 243149076adSWarner Losh sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL; 244149076adSWarner Losh } 245149076adSWarner Losh /* 246149076adSWarner Losh * If there's already a handler installed then something has 247149076adSWarner Losh * gone horribly wrong, so don't even try to handle that case. 248149076adSWarner Losh * Install some handlers for our own use. We need at least 249149076adSWarner Losh * SIGSEGV and SIGBUS, to detect exceptions. We can not just 250149076adSWarner Losh * trap all signals because it affects syscall interrupt 251149076adSWarner Losh * behavior. But do trap all default-fatal signals. 252149076adSWarner Losh */ 253149076adSWarner Losh if (fatal_signal(i)) { 254149076adSWarner Losh sigaction(host_sig, &act, NULL); 255149076adSWarner Losh } 256149076adSWarner Losh } 25784778508Sblueswir1 } 25884778508Sblueswir1 2599349b4f9SAndreas Färber void process_pending_signals(CPUArchState *cpu_env) 26084778508Sblueswir1 { 26184778508Sblueswir1 } 262835b04edSWarner Losh 263835b04edSWarner Losh void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, 264835b04edSWarner Losh MMUAccessType access_type, bool maperr, uintptr_t ra) 265835b04edSWarner Losh { 266fc9f9bddSWarner Losh const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; 267fc9f9bddSWarner Losh 268fc9f9bddSWarner Losh if (tcg_ops->record_sigsegv) { 269fc9f9bddSWarner Losh tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra); 270fc9f9bddSWarner Losh } 271fc9f9bddSWarner Losh 272fc9f9bddSWarner Losh force_sig_fault(TARGET_SIGSEGV, 273fc9f9bddSWarner Losh maperr ? TARGET_SEGV_MAPERR : TARGET_SEGV_ACCERR, 274fc9f9bddSWarner Losh addr); 275fc9f9bddSWarner Losh cpu->exception_index = EXCP_INTERRUPT; 276fc9f9bddSWarner Losh cpu_loop_exit_restore(cpu, ra); 277835b04edSWarner Losh } 278835b04edSWarner Losh 279835b04edSWarner Losh void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, 280835b04edSWarner Losh MMUAccessType access_type, uintptr_t ra) 281835b04edSWarner Losh { 282cfdee273SWarner Losh const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; 283cfdee273SWarner Losh 284cfdee273SWarner Losh if (tcg_ops->record_sigbus) { 285cfdee273SWarner Losh tcg_ops->record_sigbus(cpu, addr, access_type, ra); 286cfdee273SWarner Losh } 287cfdee273SWarner Losh 288cfdee273SWarner Losh force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, addr); 289cfdee273SWarner Losh cpu->exception_index = EXCP_INTERRUPT; 290cfdee273SWarner Losh cpu_loop_exit_restore(cpu, ra); 291835b04edSWarner Losh } 292