Skip to content

Commit

Permalink
linux-user: fix use of SIGRTMIN
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
vivier committed Feb 12, 2020
1 parent 9fcff3a commit 6bc024e
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 5 deletions.
50 changes: 45 additions & 5 deletions linux-user/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions linux-user/trace-events
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 6bc024e

Please sign in to comment.