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>
This commit is contained in:
parent
9fcff3a67f
commit
6bc024e713
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user