linux-user: Split out die_with_signal
Because we trap so many signals for use by the guest, we have to take extra steps to exit properly. Acked-by: Helge Deller <deller@gmx.de> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
912ff698ca
commit
b8b50f1e9a
@ -689,13 +689,39 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
|
||||
}
|
||||
|
||||
/* abort execution with signal */
|
||||
static G_NORETURN
|
||||
void die_with_signal(int host_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(host_sig, &act, NULL);
|
||||
|
||||
kill(getpid(), host_sig);
|
||||
|
||||
/* Make sure the signal isn't masked (reusing the mask inside of act). */
|
||||
sigdelset(&act.sa_mask, host_sig);
|
||||
sigsuspend(&act.sa_mask);
|
||||
|
||||
/* unreachable */
|
||||
abort();
|
||||
}
|
||||
|
||||
static G_NORETURN
|
||||
void dump_core_and_abort(CPUArchState *env, int target_sig)
|
||||
{
|
||||
CPUState *cpu = env_cpu(env);
|
||||
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);
|
||||
@ -719,29 +745,7 @@ void dump_core_and_abort(CPUArchState *env, int target_sig)
|
||||
}
|
||||
|
||||
preexit_cleanup(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
|
||||
|
Loading…
Reference in New Issue
Block a user