There are some places where target signals and host signals aren't
correctly differentiated.  This patch addresses proper signal
translation between target and host.

* Changes variable names to be more explicit about target and host
signals.

* Calls target_to_host_signal() and host_to_target_signal() when
appropriate.

* Adds the "TARGET_" prefix to locations that were incorrectly using
host signal names.

* Moves target_to_host_signal() and host_to_target_signal() to qsignal.h
to make them available to syscall.c.
Index: qemu/linux-user/signal.c
===================================================================
--- qemu.orig/linux-user/signal.c	2007-12-12 07:12:00.000000000 -0700
+++ qemu/linux-user/signal.c	2007-12-12 11:17:26.000000000 -0700
@@ -28,6 +28,7 @@
 
 #include "qemu.h"
 #include "target_signal.h"
+#include "qsignal.h"
 
 /*
  * Enable the DEBUG define and then set the individual DEBUG_*
@@ -66,7 +67,7 @@
 static void host_signal_handler(int host_signum, siginfo_t *info,
                                 void *puc);
 
-static uint8_t host_to_target_signal_table[65] = {
+uint8_t host_to_target_signal_table[65] = {
     [SIGHUP] = TARGET_SIGHUP,
     [SIGINT] = TARGET_SIGINT,
     [SIGQUIT] = TARGET_SIGQUIT,
@@ -103,7 +104,7 @@
     [SIGSYS] = TARGET_SIGSYS,
     /* next signals stay the same */
 };
-static uint8_t target_to_host_signal_table[65];
+uint8_t target_to_host_signal_table[65];
 
 static inline int on_sig_stack(unsigned long sp)
 {
@@ -117,16 +118,6 @@
             : on_sig_stack(sp) ? SS_ONSTACK : 0);
 }
 
-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)
 {
@@ -334,13 +325,13 @@
     first_free = q;
 }
 
-/* abort execution with signal */
-void __attribute((noreturn)) force_sig(int sig)
+/* abort execution with target signal */
+void __attribute((noreturn)) force_sig(int target_sig)
 {
     int host_sig;
-    host_sig = target_to_host_signal(sig);
+    host_sig = target_to_host_signal(target_sig);
     fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
-            sig, strsignal(host_sig));
+            target_sig, strsignal(host_sig));
 #if 1
     _exit(-host_sig);
 #else
@@ -355,23 +346,23 @@
 #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)
+/* queue a target signal so that it will be sent to the virtual CPU as
+   soon as possible */
+int queue_signal(int target_sig, target_siginfo_t *info)
 {
     struct emulated_sigaction *k;
     struct sigqueue *q, **pq;
     abi_ulong handler;
 
-    debugf(DEBUG_SIGNAL, "queue_signal: sig=%d\n", sig);
-    k = &sigact_table[sig - 1];
+    debugf(DEBUG_SIGNAL, "queue_signal: target_sig=%d\n", target_sig);
+    k = &sigact_table[target_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);
+        if (target_sig != TARGET_SIGCHLD &&
+            target_sig != TARGET_SIGURG &&
+            target_sig != TARGET_SIGWINCH) {
+            force_sig(target_sig);
         } else {
             return 0; /* indicate ignored */
         }
@@ -379,10 +370,10 @@
         /* ignore signal */
         return 0;
     } else if (handler == TARGET_SIG_ERR) {
-        force_sig(sig);
+        force_sig(target_sig);
     } else {
         pq = &k->first;
-        if (sig < TARGET_SIGRTMIN) {
+        if (target_sig < TARGET_SIGRTMIN) {
             /* if non real time signal, we queue exactly one signal */
             if (!k->pending)
                 q = &k->info;
@@ -413,7 +404,7 @@
 static void host_signal_handler(int host_signum, siginfo_t *info,
                                 void *puc)
 {
-    int sig;
+    int target_sig;
     target_siginfo_t tinfo;
 
     /* the CPU emulator uses some host signals to detect exceptions,
@@ -424,12 +415,12 @@
     }
 
     /* get target signal number */
-    sig = host_to_target_signal(host_signum);
-    if (sig < 1 || sig > TARGET_NSIG)
+    target_sig = host_to_target_signal(host_signum);
+    if (target_sig < 1 || target_sig > TARGET_NSIG)
         return;
-    debugf(DEBUG_SIGNAL, "qemu: got signal %d\n", sig);
+    debugf(DEBUG_SIGNAL, "qemu: got target signal %d\n", target_sig);
     host_to_target_siginfo_noswap(&tinfo, info);
-    if (queue_signal(sig, &tinfo) == 1) {
+    if (queue_signal(target_sig, &tinfo) == 1) {
         /* interrupt the virtual CPU as soon as possible */
         cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
     }
@@ -1343,7 +1334,7 @@
 
 badframe:
 	unlock_user_struct(frame, frame_addr, 0);
-        force_sig(SIGSEGV /* , current */);
+        force_sig(TARGET_SIGSEGV /* , current */);
 	return 0;
 }
 
@@ -1384,7 +1375,7 @@
 
 badframe:
 	unlock_user_struct(frame, frame_addr, 0);
-        force_sig(SIGSEGV /* , current */);
+        force_sig(TARGET_SIGSEGV /* , current */);
 	return 0;
 }
 
@@ -1917,7 +1908,7 @@
     return;
  do_sigsegv:
     unlock_user_struct(ucp, ucp_addr, 0);
-    force_sig(SIGSEGV);
+    force_sig(TARGET_SIGSEGV);
 }
 
 void sparc64_get_context(CPUSPARCState *env)
@@ -2011,7 +2002,7 @@
     return;
  do_sigsegv:
     unlock_user_struct(ucp, ucp_addr, 1);
-    force_sig(SIGSEGV);
+    force_sig(TARGET_SIGSEGV);
 }
 #endif
 #elif defined(TARGET_ABI_MIPSN64)
@@ -2564,7 +2555,7 @@
 
 give_sigsegv:
     unlock_user_struct(frame, frame_addr, 1);
-    force_sig(SIGSEGV);
+    force_sig(TARGET_SIGSEGV);
 }
 
 static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
@@ -2627,7 +2618,7 @@
 
 give_sigsegv:
     unlock_user_struct(frame, frame_addr, 1);
-    force_sig(SIGSEGV);
+    force_sig(TARGET_SIGSEGV);
 }
 
 long do_sigreturn(CPUState *regs)
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c	2007-12-12 07:12:14.000000000 -0700
+++ qemu/linux-user/syscall.c	2007-12-12 11:10:59.000000000 -0700
@@ -74,7 +74,9 @@
 #include <linux/kd.h>
 
 #include "qemu.h"
+#include "qsignal.h"
 #include "qspinlock.h"
+#include "debug.h"
 
 //#define DEBUG
 
@@ -3709,9 +3711,14 @@
         {
             int status;
             ret = get_errno(waitpid(arg1, &status, arg3));
-            if (!is_error(ret) && arg2
-                && put_user_s32(status, arg2))
-                goto efault;
+            if (!is_error(ret) && arg2) {
+                if (WIFSIGNALED(status)) {
+                    int hsig = host_to_target_signal(WTERMSIG(status));
+                    status = (status & ~0x7f) | hsig;
+                }
+                if (put_user_s32(status, arg2))
+                    goto efault;
+            }
         }
         break;
 #endif
@@ -4030,7 +4037,7 @@
         ret = 0;
         break;
     case TARGET_NR_kill:
-        ret = get_errno(kill(arg1, arg2));
+        ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
         break;
     case TARGET_NR_rename:
         {
@@ -5020,23 +5027,30 @@
     case TARGET_NR_wait4:
         {
             int status;
-            abi_long status_ptr = arg2;
+            abi_ulong status_addr = arg2;
             struct rusage rusage, *rusage_ptr;
-            abi_ulong target_rusage = arg4;
-            if (target_rusage)
+            abi_ulong target_rusage_addr = arg4;
+
+            if (target_rusage_addr)
                 rusage_ptr = &rusage;
             else
                 rusage_ptr = NULL;
+
             ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
-            if (!is_error(ret)) {
-                if (status_ptr) {
-                    if (put_user_s32(status, status_ptr))
-                        goto efault;
+            if (is_error(ret))
+                goto fail;
+
+            if (status_addr) {
+                if (WIFSIGNALED(status)) {
+                    int hsig = host_to_target_signal(WTERMSIG(status));
+                    status = (status & ~0x7f) | hsig;
                 }
-                if (target_rusage)
-                    if (copy_to_user_rusage(target_rusage, &rusage))
-                        goto efault;
+                if (put_user_s32(status, status_addr))
+                    goto efault;
             }
+            if (target_rusage_addr)
+                if (copy_to_user_rusage(target_rusage_addr, &rusage))
+                    goto efault;
         }
         break;
 #ifdef TARGET_NR_swapoff
Index: qemu/linux-user/qsignal.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ qemu/linux-user/qsignal.h	2007-12-12 07:12:14.000000000 -0700
@@ -0,0 +1,21 @@
+#ifndef QSIGNAL_H
+#define QSIGNAL_H
+
+#include <inttypes.h>
+
+
+extern uint8_t host_to_target_signal_table[];
+extern uint8_t target_to_host_signal_table[];
+
+
+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];
+}
+
+#endif /* QSIGNAL_H */

Reply via email to