aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-user/signal.c110
1 files changed, 99 insertions, 11 deletions
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 18cf5e242c..46abf53d89 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -60,44 +60,122 @@ 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);
-/* XXX: do it properly */
+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 sig;
+ return host_to_target_signal_table[sig];
}
static inline int target_to_host_signal(int sig)
{
- return sig;
+ return target_to_host_signal_table[sig];
}
-void host_to_target_sigset(target_sigset_t *d, sigset_t *s)
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
{
int i;
- for(i = 0;i < TARGET_NSIG_WORDS; 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] = tswapl(target_sigmask);
+ for(i = 1;i < TARGET_NSIG_WORDS; i++) {
d->sig[i] = tswapl(((unsigned long *)s)[i]);
}
+#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
+ d->sig[0] = tswapl(target_sigmask);
+ d->sig[1] = tswapl(sigmask >> 32);
+#else
+#error host_to_target_sigset
+#endif
}
-void target_to_host_sigset(sigset_t *d, target_sigset_t *s)
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
{
int i;
- for(i = 0;i < TARGET_NSIG_WORDS; i++) {
+ unsigned long sigmask;
+ target_ulong target_sigmask;
+
+ target_sigmask = tswapl(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] = tswapl(s->sig[i]);
}
+#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
+ ((unsigned long *)d)[0] = sigmask | (tswapl(s->sig[1]) << 32);
+#else
+#error target_to_host_sigset
+#endif /* TARGET_LONG_BITS */
}
void host_to_target_old_sigset(target_ulong *old_sigset,
const sigset_t *sigset)
{
- *old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff);
+ 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)
{
- sigemptyset(sigset);
- *(unsigned long *)sigset = tswapl(*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 */
@@ -167,8 +245,18 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
void signal_init(void)
{
struct sigaction act;
- int i;
+ 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);