signal.c 120 KB
Newer Older
1
/*
bellard's avatar
bellard committed
2
 *  Emulation of Linux signals
3
 *
4 5 6 7 8 9 10 11 12 13 14 15 16 17
 *  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, write to the Free Software
blueswir1's avatar
blueswir1 committed
18 19
 *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
 *  MA 02110-1301, USA.
20 21 22
 */
#include <stdlib.h>
#include <stdio.h>
bellard's avatar
bellard committed
23
#include <string.h>
24
#include <stdarg.h>
bellard's avatar
bellard committed
25
#include <unistd.h>
26
#include <signal.h>
bellard's avatar
bellard committed
27
#include <errno.h>
28
#include <assert.h>
29 30
#include <sys/ucontext.h>

bellard's avatar
bellard committed
31
#include "qemu.h"
blueswir1's avatar
blueswir1 committed
32
#include "qemu-common.h"
33
#include "target_signal.h"
bellard's avatar
bellard committed
34 35 36

//#define DEBUG_SIGNAL

37
static struct target_sigaltstack target_sigaltstack_used = {
38 39 40 41 42
    .ss_sp = 0,
    .ss_size = 0,
    .ss_flags = TARGET_SS_DISABLE,
};

pbrook's avatar
pbrook committed
43
static struct target_sigaction sigact_table[TARGET_NSIG];
44

45
static void host_signal_handler(int host_signum, siginfo_t *info,
bellard's avatar
bellard committed
46 47
                                void *puc);

bellard's avatar
bellard committed
48 49 50 51 52 53 54
static uint8_t host_to_target_signal_table[65] = {
    [SIGHUP] = TARGET_SIGHUP,
    [SIGINT] = TARGET_SIGINT,
    [SIGQUIT] = TARGET_SIGQUIT,
    [SIGILL] = TARGET_SIGILL,
    [SIGTRAP] = TARGET_SIGTRAP,
    [SIGABRT] = TARGET_SIGABRT,
bellard's avatar
bellard committed
55
/*    [SIGIOT] = TARGET_SIGIOT,*/
bellard's avatar
bellard committed
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
    [SIGBUS] = TARGET_SIGBUS,
    [SIGFPE] = TARGET_SIGFPE,
    [SIGKILL] = TARGET_SIGKILL,
    [SIGUSR1] = TARGET_SIGUSR1,
    [SIGSEGV] = TARGET_SIGSEGV,
    [SIGUSR2] = TARGET_SIGUSR2,
    [SIGPIPE] = TARGET_SIGPIPE,
    [SIGALRM] = TARGET_SIGALRM,
    [SIGTERM] = TARGET_SIGTERM,
#ifdef SIGSTKFLT
    [SIGSTKFLT] = TARGET_SIGSTKFLT,
#endif
    [SIGCHLD] = TARGET_SIGCHLD,
    [SIGCONT] = TARGET_SIGCONT,
    [SIGSTOP] = TARGET_SIGSTOP,
    [SIGTSTP] = TARGET_SIGTSTP,
    [SIGTTIN] = TARGET_SIGTTIN,
    [SIGTTOU] = TARGET_SIGTTOU,
    [SIGURG] = TARGET_SIGURG,
    [SIGXCPU] = TARGET_SIGXCPU,
    [SIGXFSZ] = TARGET_SIGXFSZ,
    [SIGVTALRM] = TARGET_SIGVTALRM,
    [SIGPROF] = TARGET_SIGPROF,
    [SIGWINCH] = TARGET_SIGWINCH,
    [SIGIO] = TARGET_SIGIO,
    [SIGPWR] = TARGET_SIGPWR,
    [SIGSYS] = TARGET_SIGSYS,
    /* next signals stay the same */
pbrook's avatar
pbrook committed
84 85 86 87 88 89
    /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
       host libpthread signals.  This assumes noone actually uses SIGRTMAX :-/
       To fix this properly we need to do manual signal delivery multiplexed
       over a single host signal.  */
    [__SIGRTMIN] = __SIGRTMAX,
    [__SIGRTMAX] = __SIGRTMIN,
bellard's avatar
bellard committed
90 91 92
};
static uint8_t target_to_host_signal_table[65];

93 94 95 96 97 98 99 100 101 102 103 104
static inline int on_sig_stack(unsigned long sp)
{
    return (sp - target_sigaltstack_used.ss_sp
            < target_sigaltstack_used.ss_size);
}

static inline int sas_ss_flags(unsigned long sp)
{
    return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
            : on_sig_stack(sp) ? SS_ONSTACK : 0);
}

105
int host_to_target_signal(int sig)
106
{
107 108
    if (sig > 64)
        return sig;
bellard's avatar
bellard committed
109
    return host_to_target_signal_table[sig];
110 111
}

112
int target_to_host_signal(int sig)
113
{
114 115
    if (sig > 64)
        return sig;
bellard's avatar
bellard committed
116
    return target_to_host_signal_table[sig];
117 118
}

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
static inline void target_sigemptyset(target_sigset_t *set)
{
    memset(set, 0, sizeof(*set));
}

static inline void target_sigaddset(target_sigset_t *set, int signum)
{
    signum--;
    abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
    set->sig[signum / TARGET_NSIG_BPW] |= mask;
}

static inline int target_sigismember(const target_sigset_t *set, int signum)
{
    signum--;
    abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
    return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
}

138
static void host_to_target_sigset_internal(target_sigset_t *d,
139
                                           const sigset_t *s)
bellard's avatar
bellard committed
140 141
{
    int i;
142 143 144 145 146
    target_sigemptyset(d);
    for (i = 1; i <= TARGET_NSIG; i++) {
        if (sigismember(s, i)) {
            target_sigaddset(d, host_to_target_signal(i));
        }
bellard's avatar
bellard committed
147 148 149
    }
}

150 151 152 153 154 155 156
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
{
    target_sigset_t d1;
    int i;

    host_to_target_sigset_internal(&d1, s);
    for(i = 0;i < TARGET_NSIG_WORDS; i++)
157
        d->sig[i] = tswapl(d1.sig[i]);
158 159
}

160 161
static void target_to_host_sigset_internal(sigset_t *d,
                                           const target_sigset_t *s)
bellard's avatar
bellard committed
162 163
{
    int i;
164 165 166 167 168 169
    sigemptyset(d);
    for (i = 1; i <= TARGET_NSIG; i++) {
        if (target_sigismember(s, i)) {
            sigaddset(d, target_to_host_signal(i));
        }
     }
bellard's avatar
bellard committed
170 171
}

172 173 174 175 176 177
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
{
    target_sigset_t s1;
    int i;

    for(i = 0;i < TARGET_NSIG_WORDS; i++)
178
        s1.sig[i] = tswapl(s->sig[i]);
179 180
    target_to_host_sigset_internal(d, &s1);
}
181

182
void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard's avatar
bellard committed
183 184
                               const sigset_t *sigset)
{
bellard's avatar
bellard committed
185 186 187
    target_sigset_t d;
    host_to_target_sigset(&d, sigset);
    *old_sigset = d.sig[0];
bellard's avatar
bellard committed
188 189
}

190
void target_to_host_old_sigset(sigset_t *sigset,
191
                               const abi_ulong *old_sigset)
bellard's avatar
bellard committed
192
{
bellard's avatar
bellard committed
193 194 195 196 197 198 199
    target_sigset_t d;
    int i;

    d.sig[0] = *old_sigset;
    for(i = 1;i < TARGET_NSIG_WORDS; i++)
        d.sig[i] = 0;
    target_to_host_sigset(sigset, &d);
bellard's avatar
bellard committed
200 201
}

bellard's avatar
bellard committed
202 203
/* siginfo conversion */

204
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard's avatar
bellard committed
205
                                                 const siginfo_t *info)
bellard's avatar
bellard committed
206
{
bellard's avatar
bellard committed
207 208 209 210
    int sig;
    sig = host_to_target_signal(info->si_signo);
    tinfo->si_signo = sig;
    tinfo->si_errno = 0;
pbrook's avatar
pbrook committed
211
    tinfo->si_code = info->si_code;
212
    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard's avatar
bellard committed
213
        sig == SIGBUS || sig == SIGTRAP) {
bellard's avatar
bellard committed
214 215 216
        /* should never come here, but who knows. The information for
           the target is irrelevant */
        tinfo->_sifields._sigfault._addr = 0;
ths's avatar
ths committed
217 218
    } else if (sig == SIGIO) {
	tinfo->_sifields._sigpoll._fd = info->si_fd;
bellard's avatar
bellard committed
219 220 221 222
    } else if (sig >= TARGET_SIGRTMIN) {
        tinfo->_sifields._rt._pid = info->si_pid;
        tinfo->_sifields._rt._uid = info->si_uid;
        /* XXX: potential problem if 64 bit */
223
        tinfo->_sifields._rt._sigval.sival_ptr =
224
            (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard's avatar
bellard committed
225 226 227
    }
}

228
static void tswap_siginfo(target_siginfo_t *tinfo,
bellard's avatar
bellard committed
229 230 231 232 233
                          const target_siginfo_t *info)
{
    int sig;
    sig = info->si_signo;
    tinfo->si_signo = tswap32(sig);
bellard's avatar
bellard committed
234 235
    tinfo->si_errno = tswap32(info->si_errno);
    tinfo->si_code = tswap32(info->si_code);
236
    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard's avatar
bellard committed
237
        sig == SIGBUS || sig == SIGTRAP) {
238
        tinfo->_sifields._sigfault._addr =
bellard's avatar
bellard committed
239
            tswapl(info->_sifields._sigfault._addr);
ths's avatar
ths committed
240 241
    } else if (sig == SIGIO) {
	tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
bellard's avatar
bellard committed
242 243 244
    } else if (sig >= TARGET_SIGRTMIN) {
        tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
        tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
245
        tinfo->_sifields._rt._sigval.sival_ptr =
bellard's avatar
bellard committed
246 247 248 249 250 251 252 253 254
            tswapl(info->_sifields._rt._sigval.sival_ptr);
    }
}


void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
{
    host_to_target_siginfo_noswap(tinfo, info);
    tswap_siginfo(tinfo, tinfo);
bellard's avatar
bellard committed
255 256
}

bellard's avatar
bellard committed
257
/* XXX: we support only POSIX RT signals are used. */
ths's avatar
ths committed
258
/* XXX: find a solution for 64 bit (additional malloced data is needed) */
bellard's avatar
bellard committed
259
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard's avatar
bellard committed
260 261 262 263
{
    info->si_signo = tswap32(tinfo->si_signo);
    info->si_errno = tswap32(tinfo->si_errno);
    info->si_code = tswap32(tinfo->si_code);
bellard's avatar
bellard committed
264 265
    info->si_pid = tswap32(tinfo->_sifields._rt._pid);
    info->si_uid = tswap32(tinfo->_sifields._rt._uid);
266
    info->si_value.sival_ptr =
267
            (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
bellard's avatar
bellard committed
268 269
}

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
static int fatal_signal (int sig)
{
    switch (sig) {
    case TARGET_SIGCHLD:
    case TARGET_SIGURG:
    case TARGET_SIGWINCH:
        /* Ignored by default.  */
        return 0;
    case TARGET_SIGCONT:
    case TARGET_SIGSTOP:
    case TARGET_SIGTSTP:
    case TARGET_SIGTTIN:
    case TARGET_SIGTTOU:
        /* Job control signals.  */
        return 0;
    default:
        return 1;
    }
}

290 291 292
void signal_init(void)
{
    struct sigaction act;
pbrook's avatar
pbrook committed
293
    struct sigaction oact;
bellard's avatar
bellard committed
294
    int i, j;
pbrook's avatar
pbrook committed
295
    int host_sig;
296

bellard's avatar
bellard committed
297 298 299 300 301 302 303 304 305
    /* generate signal conversion tables */
    for(i = 1; i <= 64; i++) {
        if (host_to_target_signal_table[i] == 0)
            host_to_target_signal_table[i] = i;
    }
    for(i = 1; i <= 64; i++) {
        j = host_to_target_signal_table[i];
        target_to_host_signal_table[j] = i;
    }
306

bellard's avatar
bellard committed
307 308
    /* set all host signal handlers. ALL signals are blocked during
       the handlers to serialize them. */
pbrook's avatar
pbrook committed
309 310
    memset(sigact_table, 0, sizeof(sigact_table));

bellard's avatar
bellard committed
311
    sigfillset(&act.sa_mask);
312 313
    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = host_signal_handler;
pbrook's avatar
pbrook committed
314 315 316 317 318 319 320 321 322 323
    for(i = 1; i <= TARGET_NSIG; i++) {
        host_sig = target_to_host_signal(i);
        sigaction(host_sig, NULL, &oact);
        if (oact.sa_sigaction == (void *)SIG_IGN) {
            sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
        } else if (oact.sa_sigaction == (void *)SIG_DFL) {
            sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
        }
        /* If there's already a handler installed then something has
           gone horribly wrong, so don't even try to handle that case.  */
324 325 326 327 328
        /* Install some handlers for our own use.  We need at least
           SIGSEGV and SIGBUS, to detect exceptions.  We can not just
           trap all signals because it affects syscall interrupt
           behavior.  But do trap all default-fatal signals.  */
        if (fatal_signal (i))
pbrook's avatar
pbrook committed
329
            sigaction(host_sig, &act, NULL);
330
    }
bellard's avatar
bellard committed
331 332 333 334
}

/* signal queue handling */

pbrook's avatar
pbrook committed
335
static inline struct sigqueue *alloc_sigqueue(CPUState *env)
bellard's avatar
bellard committed
336
{
pbrook's avatar
pbrook committed
337 338
    TaskState *ts = env->opaque;
    struct sigqueue *q = ts->first_free;
bellard's avatar
bellard committed
339 340
    if (!q)
        return NULL;
pbrook's avatar
pbrook committed
341
    ts->first_free = q->next;
bellard's avatar
bellard committed
342
    return q;
343 344
}

pbrook's avatar
pbrook committed
345
static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
bellard's avatar
bellard committed
346
{
pbrook's avatar
pbrook committed
347 348 349
    TaskState *ts = env->opaque;
    q->next = ts->first_free;
    ts->first_free = q;
bellard's avatar
bellard committed
350 351
}

bellard's avatar
bellard committed
352
/* abort execution with signal */
malc's avatar
malc committed
353
static void QEMU_NORETURN force_sig(int sig)
bellard's avatar
bellard committed
354 355
{
    int host_sig;
356
    struct sigaction act;
bellard's avatar
bellard committed
357
    host_sig = target_to_host_signal(sig);
358
    fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
bellard's avatar
bellard committed
359
            sig, strsignal(host_sig));
360
    gdb_signalled(thread_env, sig);
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383

    /* The proper exit code for dieing from an uncaught signal is
     * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
     * a negative value.  To get the proper exit code we need to
     * actually die from an uncaught signal.  Here the default signal
     * handler is installed, we send ourself a signal and we wait for
     * it to arrive. */
    sigfillset(&act.sa_mask);
    act.sa_handler = SIG_DFL;
    sigaction(host_sig, &act, NULL);

    /* For some reason raise(host_sig) doesn't send the signal when
     * statically linked on x86-64. */
    kill(getpid(), host_sig);

    /* Make sure the signal isn't masked (just reuse the mask inside
    of act) */
    sigdelset(&act.sa_mask, host_sig);
    sigsuspend(&act.sa_mask);

    /* unreachable */
    assert(0);

bellard's avatar
bellard committed
384 385
}

bellard's avatar
bellard committed
386 387
/* queue a signal so that it will be send to the virtual CPU as soon
   as possible */
pbrook's avatar
pbrook committed
388
int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
389
{
pbrook's avatar
pbrook committed
390 391
    TaskState *ts = env->opaque;
    struct emulated_sigtable *k;
bellard's avatar
bellard committed
392
    struct sigqueue *q, **pq;
393
    abi_ulong handler;
394
    int queue;
bellard's avatar
bellard committed
395

bellard's avatar
bellard committed
396
#if defined(DEBUG_SIGNAL)
397
    fprintf(stderr, "queue_signal: sig=%d\n",
bellard's avatar
bellard committed
398
            sig);
bellard's avatar
bellard committed
399
#endif
pbrook's avatar
pbrook committed
400
    k = &ts->sigtab[sig - 1];
401
    queue = gdb_queuesig ();
pbrook's avatar
pbrook committed
402
    handler = sigact_table[sig - 1]._sa_handler;
403
    if (!queue && handler == TARGET_SIG_DFL) {
404 405 406 407
        if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
            kill(getpid(),SIGSTOP);
            return 0;
        } else
bellard's avatar
bellard committed
408
        /* default handler : ignore some signal. The other are fatal */
409 410
        if (sig != TARGET_SIGCHLD &&
            sig != TARGET_SIGURG &&
411 412
            sig != TARGET_SIGWINCH &&
            sig != TARGET_SIGCONT) {
bellard's avatar
bellard committed
413
            force_sig(sig);
bellard's avatar
bellard committed
414 415
        } else {
            return 0; /* indicate ignored */
bellard's avatar
bellard committed
416
        }
417
    } else if (!queue && handler == TARGET_SIG_IGN) {
bellard's avatar
bellard committed
418
        /* ignore signal */
bellard's avatar
bellard committed
419
        return 0;
420
    } else if (!queue && handler == TARGET_SIG_ERR) {
bellard's avatar
bellard committed
421 422
        force_sig(sig);
    } else {
bellard's avatar
bellard committed
423 424 425 426 427 428 429 430 431 432 433 434
        pq = &k->first;
        if (sig < TARGET_SIGRTMIN) {
            /* if non real time signal, we queue exactly one signal */
            if (!k->pending)
                q = &k->info;
            else
                return 0;
        } else {
            if (!k->pending) {
                /* first signal */
                q = &k->info;
            } else {
pbrook's avatar
pbrook committed
435
                q = alloc_sigqueue(env);
bellard's avatar
bellard committed
436 437 438 439 440 441 442 443 444 445 446
                if (!q)
                    return -EAGAIN;
                while (*pq != NULL)
                    pq = &(*pq)->next;
            }
        }
        *pq = q;
        q->info = *info;
        q->next = NULL;
        k->pending = 1;
        /* signal that a new signal is pending */
pbrook's avatar
pbrook committed
447
        ts->signal_pending = 1;
bellard's avatar
bellard committed
448 449 450 451
        return 1; /* indicates that the signal was queued */
    }
}

452
static void host_signal_handler(int host_signum, siginfo_t *info,
bellard's avatar
bellard committed
453 454 455 456 457 458
                                void *puc)
{
    int sig;
    target_siginfo_t tinfo;

    /* the CPU emulator uses some host signals to detect exceptions,
459
       we forward to it some signals */
460
    if ((host_signum == SIGSEGV || host_signum == SIGBUS)
461
        && info->si_code > 0) {
bellard's avatar
bellard committed
462
        if (cpu_signal_handler(host_signum, info, puc))
bellard's avatar
bellard committed
463 464 465 466 467 468 469 470
            return;
    }

    /* get target signal number */
    sig = host_to_target_signal(host_signum);
    if (sig < 1 || sig > TARGET_NSIG)
        return;
#if defined(DEBUG_SIGNAL)
bellard's avatar
bellard committed
471
    fprintf(stderr, "qemu: got signal %d\n", sig);
bellard's avatar
bellard committed
472 473
#endif
    host_to_target_siginfo_noswap(&tinfo, info);
pbrook's avatar
pbrook committed
474
    if (queue_signal(thread_env, sig, &tinfo) == 1) {
bellard's avatar
bellard committed
475
        /* interrupt the virtual CPU as soon as possible */
476
        cpu_exit(thread_env);
bellard's avatar
bellard committed
477 478 479
    }
}

480
/* do_sigaltstack() returns target values and errnos. */
481 482
/* compare linux/kernel/signal.c:do_sigaltstack() */
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
483 484 485 486 487
{
    int ret;
    struct target_sigaltstack oss;

    /* XXX: test errors */
488
    if(uoss_addr)
489 490 491 492 493 494
    {
        __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
        __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
        __put_user(sas_ss_flags(sp), &oss.ss_flags);
    }

495
    if(uss_addr)
496
    {
497 498
        struct target_sigaltstack *uss;
        struct target_sigaltstack ss;
499

500
	ret = -TARGET_EFAULT;
501
        if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
502 503 504 505
	    || __get_user(ss.ss_sp, &uss->ss_sp)
	    || __get_user(ss.ss_size, &uss->ss_size)
	    || __get_user(ss.ss_flags, &uss->ss_flags))
            goto out;
506
        unlock_user_struct(uss, uss_addr, 0);
507

508
	ret = -TARGET_EPERM;
509 510 511
	if (on_sig_stack(sp))
            goto out;

512
	ret = -TARGET_EINVAL;
513 514 515 516 517 518 519 520 521
	if (ss.ss_flags != TARGET_SS_DISABLE
            && ss.ss_flags != TARGET_SS_ONSTACK
            && ss.ss_flags != 0)
            goto out;

	if (ss.ss_flags == TARGET_SS_DISABLE) {
            ss.ss_size = 0;
            ss.ss_sp = 0;
	} else {
522
            ret = -TARGET_ENOMEM;
523 524 525 526 527 528 529 530
            if (ss.ss_size < MINSIGSTKSZ)
                goto out;
	}

        target_sigaltstack_used.ss_sp = ss.ss_sp;
        target_sigaltstack_used.ss_size = ss.ss_size;
    }

531
    if (uoss_addr) {
532
        ret = -TARGET_EFAULT;
533
        if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
534 535 536 537 538 539 540 541
            goto out;
    }

    ret = 0;
out:
    return ret;
}

542
/* do_sigaction() return host values and errnos */
bellard's avatar
bellard committed
543 544 545
int do_sigaction(int sig, const struct target_sigaction *act,
                 struct target_sigaction *oact)
{
pbrook's avatar
pbrook committed
546
    struct target_sigaction *k;
547 548
    struct sigaction act1;
    int host_sig;
549
    int ret = 0;
bellard's avatar
bellard committed
550

ths's avatar
ths committed
551
    if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard's avatar
bellard committed
552 553
        return -EINVAL;
    k = &sigact_table[sig - 1];
554
#if defined(DEBUG_SIGNAL)
555
    fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
bellard's avatar
bellard committed
556 557 558
            sig, (int)act, (int)oact);
#endif
    if (oact) {
pbrook's avatar
pbrook committed
559 560
        oact->_sa_handler = tswapl(k->_sa_handler);
        oact->sa_flags = tswapl(k->sa_flags);
ths's avatar
ths committed
561
#if !defined(TARGET_MIPS)
pbrook's avatar
pbrook committed
562
        oact->sa_restorer = tswapl(k->sa_restorer);
ths's avatar
ths committed
563
#endif
pbrook's avatar
pbrook committed
564
        oact->sa_mask = k->sa_mask;
bellard's avatar
bellard committed
565 566
    }
    if (act) {
pbrook's avatar
pbrook committed
567 568 569
        /* FIXME: This is not threadsafe.  */
        k->_sa_handler = tswapl(act->_sa_handler);
        k->sa_flags = tswapl(act->sa_flags);
ths's avatar
ths committed
570
#if !defined(TARGET_MIPS)
pbrook's avatar
pbrook committed
571
        k->sa_restorer = tswapl(act->sa_restorer);
ths's avatar
ths committed
572
#endif
pbrook's avatar
pbrook committed
573
        k->sa_mask = act->sa_mask;
574 575 576 577 578 579

        /* we update the host linux signal state */
        host_sig = target_to_host_signal(sig);
        if (host_sig != SIGSEGV && host_sig != SIGBUS) {
            sigfillset(&act1.sa_mask);
            act1.sa_flags = SA_SIGINFO;
pbrook's avatar
pbrook committed
580
            if (k->sa_flags & TARGET_SA_RESTART)
581 582 583 584
                act1.sa_flags |= SA_RESTART;
            /* NOTE: it is important to update the host kernel signal
               ignore state to avoid getting unexpected interrupted
               syscalls */
pbrook's avatar
pbrook committed
585
            if (k->_sa_handler == TARGET_SIG_IGN) {
586
                act1.sa_sigaction = (void *)SIG_IGN;
pbrook's avatar
pbrook committed
587
            } else if (k->_sa_handler == TARGET_SIG_DFL) {
588 589 590 591
                if (fatal_signal (sig))
                    act1.sa_sigaction = host_signal_handler;
                else
                    act1.sa_sigaction = (void *)SIG_DFL;
592 593 594
            } else {
                act1.sa_sigaction = host_signal_handler;
            }
595
            ret = sigaction(host_sig, &act1, NULL);
596
        }
bellard's avatar
bellard committed
597
    }
598
    return ret;
bellard's avatar
bellard committed
599 600
}

601
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
bellard's avatar
bellard committed
602 603 604 605 606 607
                                       const target_siginfo_t *info)
{
    tswap_siginfo(tinfo, info);
    return 0;
}

608 609 610 611 612 613
static inline int current_exec_domain_sig(int sig)
{
    return /* current->exec_domain && current->exec_domain->signal_invmap
	      && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
}

614
#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard's avatar
bellard committed
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629

/* from the Linux kernel */

struct target_fpreg {
	uint16_t significand[4];
	uint16_t exponent;
};

struct target_fpxreg {
	uint16_t significand[4];
	uint16_t exponent;
	uint16_t padding[3];
};

struct target_xmmreg {
630
	abi_ulong element[4];
bellard's avatar
bellard committed
631 632 633 634
};

struct target_fpstate {
	/* Regular FPU environment */
635 636 637 638 639 640 641
        abi_ulong       cw;
        abi_ulong       sw;
        abi_ulong       tag;
        abi_ulong       ipoff;
        abi_ulong       cssel;
        abi_ulong       dataoff;
        abi_ulong       datasel;
bellard's avatar
bellard committed
642 643 644 645 646
	struct target_fpreg	_st[8];
	uint16_t	status;
	uint16_t	magic;		/* 0xffff = regular FPU data only */

	/* FXSR FPU environment */
647 648 649
        abi_ulong       _fxsr_env[6];   /* FXSR FPU env is ignored */
        abi_ulong       mxcsr;
        abi_ulong       reserved;
bellard's avatar
bellard committed
650 651
	struct target_fpxreg	_fxsr_st[8];	/* FXSR FPU reg data is ignored */
	struct target_xmmreg	_xmm[8];
652
        abi_ulong       padding[56];
bellard's avatar
bellard committed
653 654 655 656 657 658 659 660 661
};

#define X86_FXSR_MAGIC		0x0000

struct target_sigcontext {
	uint16_t gs, __gsh;
	uint16_t fs, __fsh;
	uint16_t es, __esh;
	uint16_t ds, __dsh;
662 663 664 665 666 667 668 669 670 671 672
        abi_ulong edi;
        abi_ulong esi;
        abi_ulong ebp;
        abi_ulong esp;
        abi_ulong ebx;
        abi_ulong edx;
        abi_ulong ecx;
        abi_ulong eax;
        abi_ulong trapno;
        abi_ulong err;
        abi_ulong eip;
bellard's avatar
bellard committed
673
	uint16_t cs, __csh;
674 675
        abi_ulong eflags;
        abi_ulong esp_at_signal;
bellard's avatar
bellard committed
676
	uint16_t ss, __ssh;
677 678 679
        abi_ulong fpstate; /* pointer */
        abi_ulong oldmask;
        abi_ulong cr2;
bellard's avatar
bellard committed
680 681 682
};

struct target_ucontext {
683 684
        abi_ulong         tuc_flags;
        abi_ulong         tuc_link;
bellard's avatar
bellard committed
685 686 687
	target_stack_t	  tuc_stack;
	struct target_sigcontext tuc_mcontext;
	target_sigset_t	  tuc_sigmask;	/* mask last for extensibility */
bellard's avatar
bellard committed
688 689 690 691
};

struct sigframe
{
692
    abi_ulong pretcode;
bellard's avatar
bellard committed
693 694 695
    int sig;
    struct target_sigcontext sc;
    struct target_fpstate fpstate;
696
    abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard's avatar
bellard committed
697 698 699 700 701
    char retcode[8];
};

struct rt_sigframe
{
702
    abi_ulong pretcode;
bellard's avatar
bellard committed
703
    int sig;
704 705
    abi_ulong pinfo;
    abi_ulong puc;
bellard's avatar
bellard committed
706 707 708 709 710 711 712 713 714 715 716 717 718
    struct target_siginfo info;
    struct target_ucontext uc;
    struct target_fpstate fpstate;
    char retcode[8];
};

/*
 * Set up a signal frame.
 */

/* XXX: save x87 state */
static int
setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard's avatar
bellard committed
719
		 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard's avatar
bellard committed
720 721
{
	int err = 0;
722
        uint16_t magic;
bellard's avatar
bellard committed
723

724
	/* already locked in setup_frame() */
725 726 727 728
	err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
	err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
	err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
	err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard's avatar
bellard committed
729 730 731 732 733 734 735 736
	err |= __put_user(env->regs[R_EDI], &sc->edi);
	err |= __put_user(env->regs[R_ESI], &sc->esi);
	err |= __put_user(env->regs[R_EBP], &sc->ebp);
	err |= __put_user(env->regs[R_ESP], &sc->esp);
	err |= __put_user(env->regs[R_EBX], &sc->ebx);
	err |= __put_user(env->regs[R_EDX], &sc->edx);
	err |= __put_user(env->regs[R_ECX], &sc->ecx);
	err |= __put_user(env->regs[R_EAX], &sc->eax);
737 738
	err |= __put_user(env->exception_index, &sc->trapno);
	err |= __put_user(env->error_code, &sc->err);
bellard's avatar
bellard committed
739
	err |= __put_user(env->eip, &sc->eip);
740
	err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard's avatar
bellard committed
741 742
	err |= __put_user(env->eflags, &sc->eflags);
	err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
743
	err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellard's avatar
bellard committed
744

bellard's avatar
bellard committed
745
        cpu_x86_fsave(env, fpstate_addr, 1);
bellard's avatar
bellard committed
746
        fpstate->status = fpstate->sw;
747 748
        magic = 0xffff;
        err |= __put_user(magic, &fpstate->magic);
bellard's avatar
bellard committed
749
        err |= __put_user(fpstate_addr, &sc->fpstate);
bellard's avatar
bellard committed
750

bellard's avatar
bellard committed
751 752
	/* non-iBCS2 extensions.. */
	err |= __put_user(mask, &sc->oldmask);
753
	err |= __put_user(env->cr[2], &sc->cr2);
bellard's avatar
bellard committed
754
	return err;
755 756
}

bellard's avatar
bellard committed
757 758 759
/*
 * Determine which stack to use..
 */
760

761
static inline abi_ulong
pbrook's avatar
pbrook committed
762
get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
763
{
bellard's avatar
bellard committed
764 765 766 767 768
	unsigned long esp;

	/* Default to using normal stack */
	esp = env->regs[R_ESP];
	/* This is the X/Open sanctioned signal stack switching.  */
pbrook's avatar
pbrook committed
769
        if (ka->sa_flags & TARGET_SA_ONSTACK) {
770 771 772
            if (sas_ss_flags(esp) == 0)
                esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
        }
bellard's avatar
bellard committed
773 774

	/* This is the legacy signal stack switching. */
775
	else
776
        if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook's avatar
pbrook committed
777 778 779
            !(ka->sa_flags & TARGET_SA_RESTORER) &&
            ka->sa_restorer) {
            esp = (unsigned long) ka->sa_restorer;
780
	}
781
        return (esp - frame_size) & -8ul;
bellard's avatar
bellard committed
782 783
}

784
/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook's avatar
pbrook committed
785
static void setup_frame(int sig, struct target_sigaction *ka,
bellard's avatar
bellard committed
786 787
			target_sigset_t *set, CPUX86State *env)
{
788
	abi_ulong frame_addr;
bellard's avatar
bellard committed
789
	struct sigframe *frame;
790
	int i, err = 0;
bellard's avatar
bellard committed
791

792
	frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard's avatar
bellard committed
793

794
	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard's avatar
bellard committed
795
		goto give_sigsegv;
796

797
	err |= __put_user(current_exec_domain_sig(sig),
bellard's avatar
bellard committed
798 799 800 801
		          &frame->sig);
	if (err)
		goto give_sigsegv;

bellard's avatar
bellard committed
802 803
	setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
                         frame_addr + offsetof(struct sigframe, fpstate));
bellard's avatar
bellard committed
804 805 806
	if (err)
		goto give_sigsegv;

807 808 809 810
        for(i = 1; i < TARGET_NSIG_WORDS; i++) {
            if (__put_user(set->sig[i], &frame->extramask[i - 1]))
                goto give_sigsegv;
        }
bellard's avatar
bellard committed
811 812 813

	/* Set up to return from userspace.  If provided, use a stub
	   already in userspace.  */
pbrook's avatar
pbrook committed
814 815
	if (ka->sa_flags & TARGET_SA_RESTORER) {
		err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard's avatar
bellard committed
816
	} else {
817
                uint16_t val16;
bellard's avatar
bellard committed
818 819 820
                abi_ulong retcode_addr;
                retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
		err |= __put_user(retcode_addr, &frame->pretcode);
bellard's avatar
bellard committed
821
		/* This is popl %eax ; movl $,%eax ; int $0x80 */
822 823
                val16 = 0xb858;
		err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard's avatar
bellard committed
824
		err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
825 826
                val16 = 0x80cd;
		err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard's avatar
bellard committed
827 828 829 830 831 832
	}

	if (err)
		goto give_sigsegv;

	/* Set up registers for signal handler */
bellard's avatar
bellard committed
833
	env->regs[R_ESP] = frame_addr;
pbrook's avatar
pbrook committed
834
	env->eip = ka->_sa_handler;
bellard's avatar
bellard committed
835 836 837 838 839 840 841

        cpu_x86_load_seg(env, R_DS, __USER_DS);
        cpu_x86_load_seg(env, R_ES, __USER_DS);
        cpu_x86_load_seg(env, R_SS, __USER_DS);
        cpu_x86_load_seg(env, R_CS, __USER_CS);
	env->eflags &= ~TF_MASK;

842 843
	unlock_user_struct(frame, frame_addr, 1);

bellard's avatar
bellard committed
844 845 846
	return;

give_sigsegv:
847
	unlock_user_struct(frame, frame_addr, 1);
bellard's avatar
bellard committed
848
	if (sig == TARGET_SIGSEGV)
pbrook's avatar
pbrook committed
849
		ka->_sa_handler = TARGET_SIG_DFL;
bellard's avatar
bellard committed
850 851 852
	force_sig(TARGET_SIGSEGV /* , current */);
}

853
/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook's avatar
pbrook committed
854
static void setup_rt_frame(int sig, struct target_sigaction *ka,
bellard's avatar
bellard committed
855
                           target_siginfo_t *info,
bellard's avatar
bellard committed
856 857
			   target_sigset_t *set, CPUX86State *env)
{
bellard's avatar
bellard committed
858
        abi_ulong frame_addr, addr;
bellard's avatar
bellard committed
859
	struct rt_sigframe *frame;
860
	int i, err = 0;
bellard's avatar
bellard committed
861

862
	frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard's avatar
bellard committed
863

864
	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard's avatar
bellard committed
865 866
		goto give_sigsegv;

867
	err |= __put_user(current_exec_domain_sig(sig),
bellard's avatar
bellard committed
868
			  &frame->sig);
bellard's avatar
bellard committed
869 870 871 872
        addr = frame_addr + offsetof(struct rt_sigframe, info);
	err |= __put_user(addr, &frame->pinfo);
        addr = frame_addr + offsetof(struct rt_sigframe, uc);
	err |= __put_user(addr, &frame->puc);
bellard's avatar
bellard committed
873 874 875
	err |= copy_siginfo_to_user(&frame->info, info);
	if (err)
		goto give_sigsegv;
876

bellard's avatar
bellard committed
877
	/* Create the ucontext.  */
bellard's avatar
bellard committed
878 879
	err |= __put_user(0, &frame->uc.tuc_flags);
	err |= __put_user(0, &frame->uc.tuc_link);
880
	err |= __put_user(target_sigaltstack_used.ss_sp,
bellard's avatar
bellard committed
881
			  &frame->uc.tuc_stack.ss_sp);
882
	err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellard's avatar
bellard committed
883
			  &frame->uc.tuc_stack.ss_flags);
884
	err |= __put_user(target_sigaltstack_used.ss_size,
bellard's avatar
bellard committed
885 886
			  &frame->uc.tuc_stack.ss_size);
	err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard's avatar
bellard committed
887 888
			        env, set->sig[0], 
                                frame_addr + offsetof(struct rt_sigframe, fpstate));
889
        for(i = 0; i < TARGET_NSIG_WORDS; i++) {