linux-user: fix use of SIGRTMIN

Some RT signals can be in use by glibc,
it's why SIGRTMIN (34) is generally greater than __SIGRTMIN (32).

So SIGRTMIN cannot be mapped to TARGET_SIGRTMIN.

Instead of swapping only SIGRTMIN and SIGRTMAX, map all the
range [TARGET_SIGRTMIN ... TARGET_SIGRTMAX - X] to
      [__SIGRTMIN + X ... SIGRTMAX ]
(SIGRTMIN is __SIGRTMIN + X).

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Reviewed-by: Taylor Simson <tsimpson@quicinc.com>
Tested-by: Taylor Simpson <tsimpson@quicinc.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-Id: <20200212125658.644558-5-laurent@vivier.eu>
master
Laurent Vivier 2020-02-12 13:56:58 +01:00
parent 9fcff3a67f
commit 6bc024e713
2 changed files with 48 additions and 5 deletions

View File

@ -498,18 +498,30 @@ static int core_dump_signal(int sig)
static void signal_table_init(void)
{
int host_sig, target_sig;
int host_sig, target_sig, count;
/*
* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
* host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
* Signals are supported starting from TARGET_SIGRTMIN and going up
* until we run out of host realtime signals.
* glibc at least uses only the lower 2 rt signals and probably
* nobody's using the upper ones.
* it's why SIGRTMIN (34) is generally greater than __SIGRTMIN (32)
* To fix this properly we need to do manual signal delivery multiplexed
* over a single host signal.
* Attempts for configure "missing" signals via sigaction will be
* silently ignored.
*/
host_to_target_signal_table[__SIGRTMIN] = __SIGRTMAX;
host_to_target_signal_table[__SIGRTMAX] = __SIGRTMIN;
for (host_sig = SIGRTMIN; host_sig <= SIGRTMAX; host_sig++) {
target_sig = host_sig - SIGRTMIN + TARGET_SIGRTMIN;
if (target_sig <= TARGET_NSIG) {
host_to_target_signal_table[host_sig] = target_sig;
}
}
/* generate signal conversion tables */
for (target_sig = 1; target_sig <= TARGET_NSIG; target_sig++) {
target_to_host_signal_table[target_sig] = _NSIG; /* poison */
}
for (host_sig = 1; host_sig < _NSIG; host_sig++) {
if (host_to_target_signal_table[host_sig] == 0) {
host_to_target_signal_table[host_sig] = host_sig;
@ -519,6 +531,15 @@ static void signal_table_init(void)
target_to_host_signal_table[target_sig] = host_sig;
}
}
if (trace_event_get_state_backends(TRACE_SIGNAL_TABLE_INIT)) {
for (target_sig = 1, count = 0; target_sig <= TARGET_NSIG; target_sig++) {
if (target_to_host_signal_table[target_sig] == _NSIG) {
count++;
}
}
trace_signal_table_init(count);
}
}
void signal_init(void)
@ -817,6 +838,8 @@ int do_sigaction(int sig, const struct target_sigaction *act,
int host_sig;
int ret = 0;
trace_signal_do_sigaction_guest(sig, TARGET_NSIG);
if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP) {
return -TARGET_EINVAL;
}
@ -847,6 +870,23 @@ int do_sigaction(int sig, const struct target_sigaction *act,
/* we update the host linux signal state */
host_sig = target_to_host_signal(sig);
trace_signal_do_sigaction_host(host_sig, TARGET_NSIG);
if (host_sig > SIGRTMAX) {
/* we don't have enough host signals to map all target signals */
qemu_log_mask(LOG_UNIMP, "Unsupported target signal #%d, ignored\n",
sig);
/*
* we don't return an error here because some programs try to
* register an handler for all possible rt signals even if they
* don't need it.
* An error here can abort them whereas there can be no problem
* to not have the signal available later.
* This is the case for golang,
* See https://github.com/golang/go/issues/33746
* So we silently ignore the error.
*/
return 0;
}
if (host_sig != SIGSEGV && host_sig != SIGBUS) {
sigfillset(&act1.sa_mask);
act1.sa_flags = SA_SIGINFO;

View File

@ -1,6 +1,9 @@
# See docs/devel/tracing.txt for syntax documentation.
# signal.c
signal_table_init(int i) "number of unavailable signals: %d"
signal_do_sigaction_guest(int sig, int max) "target signal %d (MAX %d)"
signal_do_sigaction_host(int sig, int max) "host signal %d (MAX %d)"
# */signal.c
user_setup_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
user_setup_rt_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64