linux-user: Fix siginfo handling

Compare signal numbers in the proper domain.
Convert all of the fields for SIGIO and SIGCHLD.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
This commit is contained in:
Richard Henderson 2012-09-15 11:34:20 -07:00 committed by Riku Voipio
parent b7fb231013
commit a05c640915
3 changed files with 44 additions and 20 deletions

View File

@ -219,6 +219,9 @@ unsigned long init_guest_space(unsigned long host_start,
#include "qemu-log.h" #include "qemu-log.h"
/* syscall.c */
int host_to_target_waitstatus(int status);
/* strace.c */ /* strace.c */
void print_syscall(int num, void print_syscall(int num,
abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg1, abi_long arg2, abi_long arg3,

View File

@ -202,46 +202,67 @@ void target_to_host_old_sigset(sigset_t *sigset,
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
const siginfo_t *info) const siginfo_t *info)
{ {
int sig; int sig = host_to_target_signal(info->si_signo);
sig = host_to_target_signal(info->si_signo);
tinfo->si_signo = sig; tinfo->si_signo = sig;
tinfo->si_errno = 0; tinfo->si_errno = 0;
tinfo->si_code = info->si_code; tinfo->si_code = info->si_code;
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
sig == SIGBUS || sig == SIGTRAP) { if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
/* should never come here, but who knows. The information for || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
the target is irrelevant */ /* Should never come here, but who knows. The information for
the target is irrelevant. */
tinfo->_sifields._sigfault._addr = 0; tinfo->_sifields._sigfault._addr = 0;
} else if (sig == SIGIO) { } else if (sig == TARGET_SIGIO) {
tinfo->_sifields._sigpoll._band = info->si_band;
tinfo->_sifields._sigpoll._fd = info->si_fd; tinfo->_sifields._sigpoll._fd = info->si_fd;
} else if (sig == TARGET_SIGCHLD) {
tinfo->_sifields._sigchld._pid = info->si_pid;
tinfo->_sifields._sigchld._uid = info->si_uid;
tinfo->_sifields._sigchld._status
= host_to_target_waitstatus(info->si_status);
tinfo->_sifields._sigchld._utime = info->si_utime;
tinfo->_sifields._sigchld._stime = info->si_stime;
} else if (sig >= TARGET_SIGRTMIN) { } else if (sig >= TARGET_SIGRTMIN) {
tinfo->_sifields._rt._pid = info->si_pid; tinfo->_sifields._rt._pid = info->si_pid;
tinfo->_sifields._rt._uid = info->si_uid; tinfo->_sifields._rt._uid = info->si_uid;
/* XXX: potential problem if 64 bit */ /* XXX: potential problem if 64 bit */
tinfo->_sifields._rt._sigval.sival_ptr = tinfo->_sifields._rt._sigval.sival_ptr
(abi_ulong)(unsigned long)info->si_value.sival_ptr; = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
} }
} }
static void tswap_siginfo(target_siginfo_t *tinfo, static void tswap_siginfo(target_siginfo_t *tinfo,
const target_siginfo_t *info) const target_siginfo_t *info)
{ {
int sig; int sig = info->si_signo;
sig = info->si_signo;
tinfo->si_signo = tswap32(sig); tinfo->si_signo = tswap32(sig);
tinfo->si_errno = tswap32(info->si_errno); tinfo->si_errno = tswap32(info->si_errno);
tinfo->si_code = tswap32(info->si_code); tinfo->si_code = tswap32(info->si_code);
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
sig == SIGBUS || sig == SIGTRAP) { if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
tinfo->_sifields._sigfault._addr = || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
tswapal(info->_sifields._sigfault._addr); tinfo->_sifields._sigfault._addr
} else if (sig == SIGIO) { = tswapal(info->_sifields._sigfault._addr);
tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd); } else if (sig == TARGET_SIGIO) {
tinfo->_sifields._sigpoll._band
= tswap32(info->_sifields._sigpoll._band);
tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
} else if (sig == TARGET_SIGCHLD) {
tinfo->_sifields._sigchld._pid
= tswap32(info->_sifields._sigchld._pid);
tinfo->_sifields._sigchld._uid
= tswap32(info->_sifields._sigchld._uid);
tinfo->_sifields._sigchld._status
= tswap32(info->_sifields._sigchld._status);
tinfo->_sifields._sigchld._utime
= tswapal(info->_sifields._sigchld._utime);
tinfo->_sifields._sigchld._stime
= tswapal(info->_sifields._sigchld._stime);
} else if (sig >= TARGET_SIGRTMIN) { } else if (sig >= TARGET_SIGRTMIN) {
tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid); tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid); tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
tinfo->_sifields._rt._sigval.sival_ptr = tinfo->_sifields._rt._sigval.sival_ptr
tswapal(info->_sifields._rt._sigval.sival_ptr); = tswapal(info->_sifields._rt._sigval.sival_ptr);
} }
} }

View File

@ -4918,7 +4918,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
/* Map host to target signal numbers for the wait family of syscalls. /* Map host to target signal numbers for the wait family of syscalls.
Assume all other status bits are the same. */ Assume all other status bits are the same. */
static int host_to_target_waitstatus(int status) int host_to_target_waitstatus(int status)
{ {
if (WIFSIGNALED(status)) { if (WIFSIGNALED(status)) {
return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f); return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);