Because we trap so many signals for use by the guest, we have to take extra steps to exit properly.
Signed-off-by: Richard Henderson <richard.hender...@linaro.org> --- linux-user/signal.c | 52 ++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 748a98f3e5..e1cd111a1b 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -694,6 +694,33 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, } /* abort execution with signal */ +static G_NORETURN +void die_with_signal(int sig) +{ + struct sigaction act = { + .sa_handler = SIG_DFL, + }; + + /* + * The proper exit code for dying from an uncaught signal is -<signal>. + * The kernel doesn't allow exit() or _exit() to pass a negative value. + * To get the proper exit code we need to actually die from an uncaught + * signal. Here the default signal handler is installed, we send + * the signal and we wait for it to arrive. + */ + sigfillset(&act.sa_mask); + sigaction(sig, &act, NULL); + + kill(getpid(), sig); + + /* Make sure the signal isn't masked (reusing the mask inside of act). */ + sigdelset(&act.sa_mask, sig); + sigsuspend(&act.sa_mask); + + /* unreachable */ + abort(); +} + static G_NORETURN void dump_core_and_abort(CPUArchState *cpu_env, int target_sig) { @@ -701,7 +728,6 @@ void dump_core_and_abort(CPUArchState *cpu_env, int target_sig) CPUArchState *env = cpu->env_ptr; TaskState *ts = (TaskState *)cpu->opaque; int host_sig, core_dumped = 0; - struct sigaction act; host_sig = target_to_host_signal(target_sig); trace_user_dump_core_and_abort(env, target_sig, host_sig); @@ -725,29 +751,7 @@ void dump_core_and_abort(CPUArchState *cpu_env, int target_sig) } preexit_cleanup(cpu_env, 128 + target_sig); - - /* The proper exit code for dying from an uncaught signal is - * -<signal>. The kernel doesn't allow exit() or _exit() to pass - * a negative value. To get the proper exit code we need to - * actually die from an uncaught signal. Here the default signal - * handler is installed, we send ourself a signal and we wait for - * it to arrive. */ - sigfillset(&act.sa_mask); - act.sa_handler = SIG_DFL; - act.sa_flags = 0; - sigaction(host_sig, &act, NULL); - - /* For some reason raise(host_sig) doesn't send the signal when - * statically linked on x86-64. */ - kill(getpid(), host_sig); - - /* Make sure the signal isn't masked (just reuse the mask inside - of act) */ - sigdelset(&act.sa_mask, host_sig); - sigsuspend(&act.sa_mask); - - /* unreachable */ - abort(); + die_with_signal(host_sig); } /* queue a signal so that it will be send to the virtual CPU as soon -- 2.34.1