linux-user: Remap guest SIGABRT
Distinguish host SIGABRT from guest SIGABRT by mapping the guest signal onto one of the host RT signals. This prevents a cycle by which a host assertion failure is caught and handled by host_signal_handler, queued for the guest, and then we attempt to continue past the host abort. What happens next depends on the host libc, but is neither good nor helpful. Acked-by: Helge Deller <deller@gmx.de> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
4a6ebc19a7
commit
38ee0a7dfb
@ -522,8 +522,21 @@ static void signal_table_init(void)
|
|||||||
* multiplexed over a single host signal.
|
* multiplexed over a single host signal.
|
||||||
* Attempts for configure "missing" signals via sigaction will be
|
* Attempts for configure "missing" signals via sigaction will be
|
||||||
* silently ignored.
|
* silently ignored.
|
||||||
|
*
|
||||||
|
* Remap the target SIGABRT, so that we can distinguish host abort
|
||||||
|
* from guest abort. When the guest registers a signal handler or
|
||||||
|
* calls raise(SIGABRT), the host will raise SIG_RTn. If the guest
|
||||||
|
* arrives at dump_core_and_abort(), we will map back to host SIGABRT
|
||||||
|
* so that the parent (native or emulated) sees the correct signal.
|
||||||
|
* Finally, also map host to guest SIGABRT so that the emulated
|
||||||
|
* parent sees the correct mapping from wait status.
|
||||||
*/
|
*/
|
||||||
for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) {
|
|
||||||
|
hsig = SIGRTMIN;
|
||||||
|
host_to_target_signal_table[SIGABRT] = 0;
|
||||||
|
host_to_target_signal_table[hsig++] = TARGET_SIGABRT;
|
||||||
|
|
||||||
|
for (; hsig <= SIGRTMAX; hsig++) {
|
||||||
tsig = hsig - SIGRTMIN + TARGET_SIGRTMIN;
|
tsig = hsig - SIGRTMIN + TARGET_SIGRTMIN;
|
||||||
if (tsig <= TARGET_NSIG) {
|
if (tsig <= TARGET_NSIG) {
|
||||||
host_to_target_signal_table[hsig] = tsig;
|
host_to_target_signal_table[hsig] = tsig;
|
||||||
@ -539,6 +552,8 @@ static void signal_table_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
host_to_target_signal_table[SIGABRT] = TARGET_SIGABRT;
|
||||||
|
|
||||||
/* Map everything else out-of-bounds. */
|
/* Map everything else out-of-bounds. */
|
||||||
for (hsig = 1; hsig < _NSIG; hsig++) {
|
for (hsig = 1; hsig < _NSIG; hsig++) {
|
||||||
if (host_to_target_signal_table[hsig] == 0) {
|
if (host_to_target_signal_table[hsig] == 0) {
|
||||||
@ -582,13 +597,21 @@ void signal_init(void)
|
|||||||
int hsig = target_to_host_signal(tsig);
|
int hsig = target_to_host_signal(tsig);
|
||||||
abi_ptr thand = TARGET_SIG_IGN;
|
abi_ptr thand = TARGET_SIG_IGN;
|
||||||
|
|
||||||
if (hsig < _NSIG) {
|
if (hsig >= _NSIG) {
|
||||||
struct sigaction *iact = core_dump_signal(tsig) ? &act : NULL;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As we force remap SIGABRT, cannot probe and install in one step. */
|
||||||
|
if (tsig == TARGET_SIGABRT) {
|
||||||
|
sigaction(SIGABRT, NULL, &oact);
|
||||||
|
sigaction(hsig, &act, NULL);
|
||||||
|
} else {
|
||||||
|
struct sigaction *iact = core_dump_signal(tsig) ? &act : NULL;
|
||||||
sigaction(hsig, iact, &oact);
|
sigaction(hsig, iact, &oact);
|
||||||
if (oact.sa_sigaction != (void *)SIG_IGN) {
|
}
|
||||||
thand = TARGET_SIG_DFL;
|
|
||||||
}
|
if (oact.sa_sigaction != (void *)SIG_IGN) {
|
||||||
|
thand = TARGET_SIG_DFL;
|
||||||
}
|
}
|
||||||
sigact_table[tsig - 1]._sa_handler = thand;
|
sigact_table[tsig - 1]._sa_handler = thand;
|
||||||
}
|
}
|
||||||
@ -711,7 +734,12 @@ void dump_core_and_abort(CPUArchState *env, int target_sig)
|
|||||||
TaskState *ts = (TaskState *)cpu->opaque;
|
TaskState *ts = (TaskState *)cpu->opaque;
|
||||||
int host_sig, core_dumped = 0;
|
int host_sig, core_dumped = 0;
|
||||||
|
|
||||||
host_sig = target_to_host_signal(target_sig);
|
/* On exit, undo the remapping of SIGABRT. */
|
||||||
|
if (target_sig == TARGET_SIGABRT) {
|
||||||
|
host_sig = SIGABRT;
|
||||||
|
} else {
|
||||||
|
host_sig = target_to_host_signal(target_sig);
|
||||||
|
}
|
||||||
trace_user_dump_core_and_abort(env, target_sig, host_sig);
|
trace_user_dump_core_and_abort(env, target_sig, host_sig);
|
||||||
gdb_signalled(env, target_sig);
|
gdb_signalled(env, target_sig);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user