mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-28 20:41:52 -06:00
user: Introduce host_interrupt_signal
Attaching to the gdbstub of a running process requires stopping its threads. For threads that run on a CPU, cpu_exit() is enough, but the only way to grab attention of a thread that is stuck in a long-running syscall is to interrupt it with a signal. Reserve a host realtime signal for this, just like it's already done for TARGET_SIGABRT on Linux. This may reduce the number of available guest realtime signals by one, but this is acceptable, since there are quite a lot of them, and it's unlikely that there are apps that need them all. Set signal_pending for the safe_sycall machinery to prevent invoking the syscall. This is a lie, since we don't queue a guest signal, but process_pending_signals() can handle the absence of pending signals. The syscall returns with QEMU_ERESTARTSYS errno, which arranges for the automatic restart. This is important, because it helps avoiding disturbing poorly written guests. Reviewed-by: Warner Losh <imp@bsdimp.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20250117001542.8290-5-iii@linux.ibm.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20250207153112.3939799-14-alex.bennee@linaro.org>
This commit is contained in:
parent
08916fd4b6
commit
2b3ccf5f0d
3 changed files with 34 additions and 5 deletions
|
@ -51,6 +51,8 @@ static inline int sas_ss_flags(TaskState *ts, unsigned long sp)
|
||||||
on_sig_stack(ts, sp) ? SS_ONSTACK : 0;
|
on_sig_stack(ts, sp) ? SS_ONSTACK : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int host_interrupt_signal = SIGRTMAX;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The BSD ABIs use the same signal numbers across all the CPU architectures, so
|
* The BSD ABIs use the same signal numbers across all the CPU architectures, so
|
||||||
* (unlike Linux) these functions are just the identity mapping. This might not
|
* (unlike Linux) these functions are just the identity mapping. This might not
|
||||||
|
@ -491,6 +493,12 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||||
uintptr_t pc = 0;
|
uintptr_t pc = 0;
|
||||||
bool sync_sig = false;
|
bool sync_sig = false;
|
||||||
|
|
||||||
|
if (host_sig == host_interrupt_signal) {
|
||||||
|
ts->signal_pending = 1;
|
||||||
|
cpu_exit(thread_cpu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
|
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
|
||||||
* handling wrt signal blocking and unwinding.
|
* handling wrt signal blocking and unwinding.
|
||||||
|
@ -854,6 +862,9 @@ void signal_init(void)
|
||||||
|
|
||||||
for (i = 1; i <= TARGET_NSIG; i++) {
|
for (i = 1; i <= TARGET_NSIG; i++) {
|
||||||
host_sig = target_to_host_signal(i);
|
host_sig = target_to_host_signal(i);
|
||||||
|
if (host_sig == host_interrupt_signal) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
sigaction(host_sig, NULL, &oact);
|
sigaction(host_sig, NULL, &oact);
|
||||||
if (oact.sa_sigaction == (void *)SIG_IGN) {
|
if (oact.sa_sigaction == (void *)SIG_IGN) {
|
||||||
sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
|
sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
|
||||||
|
@ -872,6 +883,7 @@ void signal_init(void)
|
||||||
sigaction(host_sig, &act, NULL);
|
sigaction(host_sig, &act, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sigaction(host_interrupt_signal, &act, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_pending_signal(CPUArchState *env, int sig,
|
static void handle_pending_signal(CPUArchState *env, int sig,
|
||||||
|
|
|
@ -20,4 +20,6 @@
|
||||||
*/
|
*/
|
||||||
int target_to_host_signal(int sig);
|
int target_to_host_signal(int sig);
|
||||||
|
|
||||||
|
extern int host_interrupt_signal;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -517,6 +517,8 @@ static int core_dump_signal(int sig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int host_interrupt_signal;
|
||||||
|
|
||||||
static void signal_table_init(const char *rtsig_map)
|
static void signal_table_init(const char *rtsig_map)
|
||||||
{
|
{
|
||||||
int hsig, tsig, count;
|
int hsig, tsig, count;
|
||||||
|
@ -580,10 +582,10 @@ static void signal_table_init(const char *rtsig_map)
|
||||||
* Attempts for configure "missing" signals via sigaction will be
|
* Attempts for configure "missing" signals via sigaction will be
|
||||||
* silently ignored.
|
* silently ignored.
|
||||||
*
|
*
|
||||||
* Reserve one signal for internal usage (see below).
|
* Reserve two signals for internal usage (see below).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hsig = SIGRTMIN + 1;
|
hsig = SIGRTMIN + 2;
|
||||||
for (tsig = TARGET_SIGRTMIN;
|
for (tsig = TARGET_SIGRTMIN;
|
||||||
hsig <= SIGRTMAX && tsig <= TARGET_NSIG;
|
hsig <= SIGRTMAX && tsig <= TARGET_NSIG;
|
||||||
hsig++, tsig++) {
|
hsig++, tsig++) {
|
||||||
|
@ -604,12 +606,17 @@ static void signal_table_init(const char *rtsig_map)
|
||||||
host_to_target_signal_table[SIGABRT] = 0;
|
host_to_target_signal_table[SIGABRT] = 0;
|
||||||
for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) {
|
for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) {
|
||||||
if (!host_to_target_signal_table[hsig]) {
|
if (!host_to_target_signal_table[hsig]) {
|
||||||
host_to_target_signal_table[hsig] = TARGET_SIGABRT;
|
if (host_interrupt_signal) {
|
||||||
break;
|
host_to_target_signal_table[hsig] = TARGET_SIGABRT;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
host_interrupt_signal = hsig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hsig > SIGRTMAX) {
|
if (hsig > SIGRTMAX) {
|
||||||
fprintf(stderr, "No rt signals left for SIGABRT mapping\n");
|
fprintf(stderr,
|
||||||
|
"No rt signals left for interrupt and SIGABRT mapping\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,6 +696,8 @@ void signal_init(const char *rtsig_map)
|
||||||
}
|
}
|
||||||
sigact_table[tsig - 1]._sa_handler = thand;
|
sigact_table[tsig - 1]._sa_handler = thand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sigaction(host_interrupt_signal, &act, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force a synchronously taken signal. The kernel force_sig() function
|
/* Force a synchronously taken signal. The kernel force_sig() function
|
||||||
|
@ -1036,6 +1045,12 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||||
bool sync_sig = false;
|
bool sync_sig = false;
|
||||||
void *sigmask;
|
void *sigmask;
|
||||||
|
|
||||||
|
if (host_sig == host_interrupt_signal) {
|
||||||
|
ts->signal_pending = 1;
|
||||||
|
cpu_exit(thread_cpu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
|
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
|
||||||
* handling wrt signal blocking and unwinding. Non-spoofed SIGILL,
|
* handling wrt signal blocking and unwinding. Non-spoofed SIGILL,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue