⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 signal.c

📁 qemu虚拟机代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  Emulation of Linux signals *  *  Copyright (c) 2003 Fabrice Bellard * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <stdarg.h>#include <unistd.h>#include <signal.h>#include <errno.h>#include <sys/ucontext.h>#include "qemu.h"//#define DEBUG_SIGNAL#define MAX_SIGQUEUE_SIZE 1024struct sigqueue {    struct sigqueue *next;    target_siginfo_t info;};struct emulated_sigaction {    struct target_sigaction sa;    int pending; /* true if signal is pending */    struct sigqueue *first;    struct sigqueue info; /* in order to always have memory for the                             first signal, we put it here */};static struct emulated_sigaction sigact_table[TARGET_NSIG];static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */static struct sigqueue *first_free; /* first free siginfo queue entry */static int signal_pending; /* non zero if a signal may be pending */static void host_signal_handler(int host_signum, siginfo_t *info,                                 void *puc);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,/*    [SIGIOT] = TARGET_SIGIOT,*/    [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 */};static uint8_t target_to_host_signal_table[65];static inline int host_to_target_signal(int sig){    return host_to_target_signal_table[sig];}static inline int target_to_host_signal(int sig){    return target_to_host_signal_table[sig];}static void host_to_target_sigset_internal(target_sigset_t *d,                                            const sigset_t *s){    int i;    unsigned long sigmask;    uint32_t target_sigmask;        sigmask = ((unsigned long *)s)[0];    target_sigmask = 0;    for(i = 0; i < 32; i++) {        if (sigmask & (1 << i))             target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);    }#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32    d->sig[0] = target_sigmask;    for(i = 1;i < TARGET_NSIG_WORDS; i++) {        d->sig[i] = ((unsigned long *)s)[i];    }#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2    d->sig[0] = target_sigmask;    d->sig[1] = sigmask >> 32;#else#warning host_to_target_sigset#endif}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++)        d->sig[i] = tswapl(d1.sig[i]);}void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s){    int i;    unsigned long sigmask;    target_ulong target_sigmask;    target_sigmask = s->sig[0];    sigmask = 0;    for(i = 0; i < 32; i++) {        if (target_sigmask & (1 << i))             sigmask |= 1 << (target_to_host_signal(i + 1) - 1);    }#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32    ((unsigned long *)d)[0] = sigmask;    for(i = 1;i < TARGET_NSIG_WORDS; i++) {        ((unsigned long *)d)[i] = s->sig[i];    }#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2    ((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32);#else#warning target_to_host_sigset#endif /* TARGET_LONG_BITS */}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++)        s1.sig[i] = tswapl(s->sig[i]);    target_to_host_sigset_internal(d, &s1);}    void host_to_target_old_sigset(target_ulong *old_sigset,                                const sigset_t *sigset){    target_sigset_t d;    host_to_target_sigset(&d, sigset);    *old_sigset = d.sig[0];}void target_to_host_old_sigset(sigset_t *sigset,                                const target_ulong *old_sigset){    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);}/* siginfo conversion */static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,                                                  const siginfo_t *info){    int sig;    sig = host_to_target_signal(info->si_signo);    tinfo->si_signo = sig;    tinfo->si_errno = 0;    tinfo->si_code = 0;    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||         sig == SIGBUS || sig == SIGTRAP) {        /* should never come here, but who knows. The information for           the target is irrelevant */        tinfo->_sifields._sigfault._addr = 0;    } 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 */        tinfo->_sifields._rt._sigval.sival_ptr =             (target_ulong)info->si_value.sival_ptr;    }}static void tswap_siginfo(target_siginfo_t *tinfo,                           const target_siginfo_t *info){    int sig;    sig = info->si_signo;    tinfo->si_signo = tswap32(sig);    tinfo->si_errno = tswap32(info->si_errno);    tinfo->si_code = tswap32(info->si_code);    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||         sig == SIGBUS || sig == SIGTRAP) {        tinfo->_sifields._sigfault._addr =             tswapl(info->_sifields._sigfault._addr);    } else if (sig >= TARGET_SIGRTMIN) {        tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);        tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);        tinfo->_sifields._rt._sigval.sival_ptr =             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);}/* XXX: we support only POSIX RT signals are used. *//* XXX: find a solution for 64 bit (additionnal malloced data is needed) */void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo){    info->si_signo = tswap32(tinfo->si_signo);    info->si_errno = tswap32(tinfo->si_errno);    info->si_code = tswap32(tinfo->si_code);    info->si_pid = tswap32(tinfo->_sifields._rt._pid);    info->si_uid = tswap32(tinfo->_sifields._rt._uid);    info->si_value.sival_ptr =         (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);}void signal_init(void){    struct sigaction act;    int i, j;    /* 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;    }            /* set all host signal handlers. ALL signals are blocked during       the handlers to serialize them. */    sigfillset(&act.sa_mask);    act.sa_flags = SA_SIGINFO;    act.sa_sigaction = host_signal_handler;    for(i = 1; i < NSIG; i++) {        sigaction(i, &act, NULL);    }        memset(sigact_table, 0, sizeof(sigact_table));    first_free = &sigqueue_table[0];    for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)         sigqueue_table[i].next = &sigqueue_table[i + 1];    sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;}/* signal queue handling */static inline struct sigqueue *alloc_sigqueue(void){    struct sigqueue *q = first_free;    if (!q)        return NULL;    first_free = q->next;    return q;}static inline void free_sigqueue(struct sigqueue *q){    q->next = first_free;    first_free = q;}/* abort execution with signal */void __attribute((noreturn)) force_sig(int sig){    int host_sig;    host_sig = target_to_host_signal(sig);    fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",             sig, strsignal(host_sig));#if 1    _exit(-host_sig);#else    {        struct sigaction act;        sigemptyset(&act.sa_mask);        act.sa_flags = SA_SIGINFO;        act.sa_sigaction = SIG_DFL;        sigaction(SIGABRT, &act, NULL);        abort();    }#endif}/* queue a signal so that it will be send to the virtual CPU as soon   as possible */int queue_signal(int sig, target_siginfo_t *info){    struct emulated_sigaction *k;    struct sigqueue *q, **pq;    target_ulong handler;#if defined(DEBUG_SIGNAL)    fprintf(stderr, "queue_signal: sig=%d\n",             sig);#endif    k = &sigact_table[sig - 1];    handler = k->sa._sa_handler;    if (handler == TARGET_SIG_DFL) {        /* default handler : ignore some signal. The other are fatal */        if (sig != TARGET_SIGCHLD &&             sig != TARGET_SIGURG &&             sig != TARGET_SIGWINCH) {            force_sig(sig);        } else {            return 0; /* indicate ignored */        }    } else if (handler == TARGET_SIG_IGN) {        /* ignore signal */        return 0;    } else if (handler == TARGET_SIG_ERR) {        force_sig(sig);    } else {        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 {                q = alloc_sigqueue();                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 */        signal_pending = 1;        return 1; /* indicates that the signal was queued */    }}static void host_signal_handler(int host_signum, siginfo_t *info,                                 void *puc){    int sig;    target_siginfo_t tinfo;    /* the CPU emulator uses some host signals to detect exceptions,       we we forward to it some signals */    if (host_signum == SIGSEGV || host_signum == SIGBUS #if defined(TARGET_I386) && defined(USE_CODE_COPY)        || host_signum == SIGFPE#endif        ) {        if (cpu_signal_handler(host_signum, info, puc))            return;    }    /* get target signal number */    sig = host_to_target_signal(host_signum);    if (sig < 1 || sig > TARGET_NSIG)        return;#if defined(DEBUG_SIGNAL)    fprintf(stderr, "qemu: got signal %d\n", sig);#endif    host_to_target_siginfo_noswap(&tinfo, info);    if (queue_signal(sig, &tinfo) == 1) {        /* interrupt the virtual CPU as soon as possible */        cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);    }}int do_sigaction(int sig, const struct target_sigaction *act,                 struct target_sigaction *oact){    struct emulated_sigaction *k;    struct sigaction act1;    int host_sig;    if (sig < 1 || sig > TARGET_NSIG)        return -EINVAL;    k = &sigact_table[sig - 1];#if defined(DEBUG_SIGNAL)    fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",             sig, (int)act, (int)oact);#endif    if (oact) {        oact->_sa_handler = tswapl(k->sa._sa_handler);        oact->sa_flags = tswapl(k->sa.sa_flags);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -