qemu/darwin-user/signal.c
<<
>>
Prefs
   1/*
   2 *  Emulation of Linux signals
   3 *
   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
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  19 *  MA 02110-1301, USA.
  20 */
  21#include <stdlib.h>
  22#include <stdio.h>
  23#include <string.h>
  24#include <stdarg.h>
  25#include <unistd.h>
  26#include <signal.h>
  27#include <errno.h>
  28#include <sys/ucontext.h>
  29
  30#ifdef __ia64__
  31#undef uc_mcontext
  32#undef uc_sigmask
  33#undef uc_stack
  34#undef uc_link
  35#endif
  36
  37#include <signal.h>
  38
  39#include "qemu.h"
  40#include "qemu-common.h"
  41
  42#define DEBUG_SIGNAL
  43
  44#define MAX_SIGQUEUE_SIZE 1024
  45
  46struct sigqueue {
  47    struct sigqueue *next;
  48    target_siginfo_t info;
  49};
  50
  51struct emulated_sigaction {
  52    struct target_sigaction sa;
  53    int pending; /* true if signal is pending */
  54    struct sigqueue *first;
  55    struct sigqueue info; /* in order to always have memory for the
  56                             first signal, we put it here */
  57};
  58
  59static struct sigaltstack target_sigaltstack_used = {
  60    0, 0, SA_DISABLE
  61};
  62
  63static struct emulated_sigaction sigact_table[NSIG];
  64static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
  65static struct sigqueue *first_free; /* first free siginfo queue entry */
  66static int signal_pending; /* non zero if a signal may be pending */
  67
  68static void host_signal_handler(int host_signum, siginfo_t *info,
  69                                void *puc);
  70
  71
  72static inline int host_to_target_signal(int sig)
  73{
  74    return sig;
  75}
  76
  77static inline int target_to_host_signal(int sig)
  78{
  79    return sig;
  80}
  81
  82/* siginfo conversion */
  83
  84
  85
  86void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
  87{
  88
  89}
  90
  91void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
  92{
  93
  94}
  95
  96void signal_init(void)
  97{
  98    struct sigaction act;
  99    int i;
 100
 101    /* set all host signal handlers. ALL signals are blocked during
 102       the handlers to serialize them. */
 103    sigfillset(&act.sa_mask);
 104    act.sa_flags = SA_SIGINFO;
 105    act.sa_sigaction = host_signal_handler;
 106    for(i = 1; i < NSIG; i++) {
 107        sigaction(i, &act, NULL);
 108    }
 109
 110    memset(sigact_table, 0, sizeof(sigact_table));
 111
 112    first_free = &sigqueue_table[0];
 113    for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
 114        sigqueue_table[i].next = &sigqueue_table[i + 1];
 115    sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
 116}
 117
 118/* signal queue handling */
 119
 120static inline struct sigqueue *alloc_sigqueue(void)
 121{
 122    struct sigqueue *q = first_free;
 123    if (!q)
 124        return NULL;
 125    first_free = q->next;
 126    return q;
 127}
 128
 129static inline void free_sigqueue(struct sigqueue *q)
 130{
 131    q->next = first_free;
 132    first_free = q;
 133}
 134
 135/* abort execution with signal */
 136void QEMU_NORETURN force_sig(int sig)
 137{
 138    int host_sig;
 139    host_sig = target_to_host_signal(sig);
 140    fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
 141            sig, strsignal(host_sig));
 142    _exit(-host_sig);
 143}
 144
 145/* queue a signal so that it will be send to the virtual CPU as soon
 146   as possible */
 147int queue_signal(int sig, target_siginfo_t *info)
 148{
 149    struct emulated_sigaction *k;
 150    struct sigqueue *q, **pq;
 151    target_ulong handler;
 152
 153#if defined(DEBUG_SIGNAL)
 154    fprintf(stderr, "queue_signal: sig=%d\n",
 155            sig);
 156#endif
 157    k = &sigact_table[sig - 1];
 158    handler = (target_ulong)k->sa.sa_handler;
 159    if (handler == SIG_DFL) {
 160        /* default handler : ignore some signal. The other are fatal */
 161        if (sig != SIGCHLD &&
 162            sig != SIGURG &&
 163            sig != SIGWINCH) {
 164            force_sig(sig);
 165        } else {
 166            return 0; /* indicate ignored */
 167        }
 168    } else if (handler == host_to_target_signal(SIG_IGN)) {
 169        /* ignore signal */
 170        return 0;
 171    } else if (handler == host_to_target_signal(SIG_ERR)) {
 172        force_sig(sig);
 173    } else {
 174        pq = &k->first;
 175        if (!k->pending) {
 176            /* first signal */
 177            q = &k->info;
 178        } else {
 179            q = alloc_sigqueue();
 180            if (!q)
 181                return -EAGAIN;
 182            while (*pq != NULL)
 183                pq = &(*pq)->next;
 184        }
 185        *pq = q;
 186        q->info = *info;
 187        q->next = NULL;
 188        k->pending = 1;
 189        /* signal that a new signal is pending */
 190        signal_pending = 1;
 191        return 1; /* indicates that the signal was queued */
 192    }
 193}
 194
 195static void host_signal_handler(int host_signum, siginfo_t *info,
 196                                void *puc)
 197{
 198    int sig;
 199    target_siginfo_t tinfo;
 200
 201    /* the CPU emulator uses some host signals to detect exceptions,
 202       we we forward to it some signals */
 203    if (host_signum == SIGSEGV || host_signum == SIGBUS) {
 204        if (cpu_signal_handler(host_signum, (void*)info, puc))
 205            return;
 206    }
 207
 208    /* get target signal number */
 209    sig = host_to_target_signal(host_signum);
 210    if (sig < 1 || sig > NSIG)
 211        return;
 212
 213#if defined(DEBUG_SIGNAL)
 214        fprintf(stderr, "qemu: got signal %d\n", sig);
 215#endif
 216    if (queue_signal(sig, &tinfo) == 1) {
 217        /* interrupt the virtual CPU as soon as possible */
 218        cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
 219    }
 220}
 221
 222int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss)
 223{
 224    /* XXX: test errors */
 225    if(oss)
 226    {
 227        oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp);
 228        oss->ss_size = tswap32(target_sigaltstack_used.ss_size);
 229        oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags);
 230    }
 231    if(ss)
 232    {
 233        target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp);
 234        target_sigaltstack_used.ss_size = tswap32(ss->ss_size);
 235        target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags);
 236    }
 237    return 0;
 238}
 239
 240int do_sigaction(int sig, const struct sigaction *act,
 241                 struct sigaction *oact)
 242{
 243    struct emulated_sigaction *k;
 244    struct sigaction act1;
 245    int host_sig;
 246
 247    if (sig < 1 || sig > NSIG)
 248        return -EINVAL;
 249
 250    k = &sigact_table[sig - 1];
 251#if defined(DEBUG_SIGNAL)
 252    fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
 253            sig, (int)act, (int)oact);
 254#endif
 255    if (oact) {
 256#if defined(DEBUG_SIGNAL)
 257    fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
 258            sig, (int)act, (int)oact);
 259#endif
 260
 261        oact->sa_handler = tswapl(k->sa.sa_handler);
 262        oact->sa_flags = tswapl(k->sa.sa_flags);
 263        oact->sa_mask = tswapl(k->sa.sa_mask);
 264    }
 265    if (act) {
 266#if defined(DEBUG_SIGNAL)
 267    fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n",
 268            act->sa_handler, act->sa_flags, act->sa_mask);
 269#endif
 270
 271        k->sa.sa_handler = tswapl(act->sa_handler);
 272        k->sa.sa_flags = tswapl(act->sa_flags);
 273        k->sa.sa_mask = tswapl(act->sa_mask);
 274        /* we update the host signal state */
 275        host_sig = target_to_host_signal(sig);
 276        if (host_sig != SIGSEGV && host_sig != SIGBUS) {
 277#if defined(DEBUG_SIGNAL)
 278    fprintf(stderr, "sigaction handler going to call sigaction\n",
 279            act->sa_handler, act->sa_flags, act->sa_mask);
 280#endif
 281
 282            sigfillset(&act1.sa_mask);
 283            act1.sa_flags = SA_SIGINFO;
 284            if (k->sa.sa_flags & SA_RESTART)
 285                act1.sa_flags |= SA_RESTART;
 286            /* NOTE: it is important to update the host kernel signal
 287               ignore state to avoid getting unexpected interrupted
 288               syscalls */
 289            if (k->sa.sa_handler == SIG_IGN) {
 290                act1.sa_sigaction = (void *)SIG_IGN;
 291            } else if (k->sa.sa_handler == SIG_DFL) {
 292                act1.sa_sigaction = (void *)SIG_DFL;
 293            } else {
 294                act1.sa_sigaction = host_signal_handler;
 295            }
 296            sigaction(host_sig, &act1, NULL);
 297        }
 298    }
 299    return 0;
 300}
 301
 302
 303#ifdef TARGET_I386
 304
 305static inline void *
 306get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
 307{
 308    /* XXX Fix that */
 309    if(target_sigaltstack_used.ss_flags & SA_DISABLE)
 310    {
 311        int esp;
 312        /* Default to using normal stack */
 313        esp = env->regs[R_ESP];
 314
 315        return (void *)((esp - frame_size) & -8ul);
 316    }
 317    else
 318    {
 319        return target_sigaltstack_used.ss_sp;
 320    }
 321}
 322
 323static void setup_frame(int sig, struct emulated_sigaction *ka,
 324                        void *set, CPUState *env)
 325{
 326        void *frame;
 327        int i, err = 0;
 328
 329    fprintf(stderr, "setup_frame %d\n", sig);
 330        frame = get_sigframe(ka, env, sizeof(*frame));
 331
 332        /* Set up registers for signal handler */
 333        env->regs[R_ESP] = (unsigned long) frame;
 334        env->eip = (unsigned long) ka->sa.sa_handler;
 335
 336        env->eflags &= ~TF_MASK;
 337
 338        return;
 339
 340give_sigsegv:
 341        if (sig == SIGSEGV)
 342                ka->sa.sa_handler = SIG_DFL;
 343        force_sig(SIGSEGV /* , current */);
 344}
 345
 346long do_sigreturn(CPUState *env, int num)
 347{
 348    int i = 0;
 349    struct target_sigcontext *scp = get_int_arg(&i, env);
 350    /* XXX Get current signal number */
 351    /* XXX Adjust accordin to sc_onstack, sc_mask */
 352    if(tswapl(scp->sc_onstack) & 0x1)
 353        target_sigaltstack_used.ss_flags |= ~SA_DISABLE;
 354    else
 355        target_sigaltstack_used.ss_flags &=  SA_DISABLE;
 356    int set = tswapl(scp->sc_eax);
 357    sigprocmask(SIG_SETMASK, &set, NULL);
 358
 359    fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx));
 360    fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi));
 361    fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip));
 362
 363    env->regs[R_EAX] = tswapl(scp->sc_eax);
 364    env->regs[R_EBX] = tswapl(scp->sc_ebx);
 365    env->regs[R_ECX] = tswapl(scp->sc_ecx);
 366    env->regs[R_EDX] = tswapl(scp->sc_edx);
 367    env->regs[R_EDI] = tswapl(scp->sc_edi);
 368    env->regs[R_ESI] = tswapl(scp->sc_esi);
 369    env->regs[R_EBP] = tswapl(scp->sc_ebp);
 370    env->regs[R_ESP] = tswapl(scp->sc_esp);
 371    env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss);
 372    env->eflags = tswapl(scp->sc_eflags);
 373    env->eip = tswapl(scp->sc_eip);
 374    env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs);
 375    env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds);
 376    env->segs[R_ES].selector = (void*)tswapl(scp->sc_es);
 377    env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs);
 378    env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs);
 379
 380    /* Again, because our caller's caller will reset EAX */
 381    return env->regs[R_EAX];
 382}
 383
 384#else
 385
 386static void setup_frame(int sig, struct emulated_sigaction *ka,
 387                        void *set, CPUState *env)
 388{
 389    fprintf(stderr, "setup_frame: not implemented\n");
 390}
 391
 392long do_sigreturn(CPUState *env, int num)
 393{
 394    int i = 0;
 395    struct target_sigcontext *scp = get_int_arg(&i, env);
 396    fprintf(stderr, "do_sigreturn: not implemented\n");
 397    return -ENOSYS;
 398}
 399
 400#endif
 401
 402void process_pending_signals(void *cpu_env)
 403{
 404    struct emulated_sigaction *k;
 405    struct sigqueue *q;
 406    target_ulong handler;
 407    int sig;
 408
 409    if (!signal_pending)
 410        return;
 411
 412    k = sigact_table;
 413
 414    for(sig = 1; sig <= NSIG; sig++) {
 415        if (k->pending)
 416            goto handle_signal;
 417        k++;
 418    }
 419
 420    /* if no signal is pending, just return */
 421    signal_pending = 0;
 422    return;
 423handle_signal:
 424    #ifdef DEBUG_SIGNAL
 425    fprintf(stderr, "qemu: process signal %d\n", sig);
 426    #endif
 427    /* dequeue signal */
 428    q = k->first;
 429    k->first = q->next;
 430    if (!k->first)
 431        k->pending = 0;
 432
 433    sig = gdb_handlesig (cpu_env, sig);
 434    if (!sig) {
 435        fprintf (stderr, "Lost signal\n");
 436        abort();
 437    }
 438
 439    handler = k->sa.sa_handler;
 440    if (handler == SIG_DFL) {
 441        /* default handler : ignore some signal. The other are fatal */
 442        if (sig != SIGCHLD &&
 443            sig != SIGURG &&
 444            sig != SIGWINCH) {
 445            force_sig(sig);
 446        }
 447    } else if (handler == SIG_IGN) {
 448        /* ignore sig */
 449    } else if (handler == SIG_ERR) {
 450        force_sig(sig);
 451    } else {
 452
 453        setup_frame(sig, k, 0, cpu_env);
 454        if (k->sa.sa_flags & SA_RESETHAND)
 455            k->sa.sa_handler = SIG_DFL;
 456    }
 457    if (q != &k->info)
 458        free_sigqueue(q);
 459}
 460