Message ID | 20220109161923.85683-11-imp@bsdimp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | bsd-user: upstream our signal implementation | expand |
On Sun, 9 Jan 2022 at 16:29, Warner Losh <imp@bsdimp.com> wrote: > > Initialize the signal state for the emulator. Setup a set of sane > default signal handlers, mirroring the host's signals. For fatal signals > (those that exit by default), establish our own set of signal > handlers. Stub out the actual signal handler we use for the moment. > > Signed-off-by: Stacey Son <sson@FreeBSD.org> > Signed-off-by: Kyle Evans <kevans@freebsd.org> > Signed-off-by: Warner Losh <imp@bsdimp.com> > --- > bsd-user/qemu.h | 1 + > bsd-user/signal.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 69 insertions(+) > +static struct target_sigaction sigact_table[TARGET_NSIG]; > void signal_init(void) > { > + TaskState *ts = (TaskState *)thread_cpu->opaque; > + struct sigaction act; > + struct sigaction oact; > + int i; > + int host_sig; > + > + /* Set the signal mask from the host mask. */ > + sigprocmask(0, 0, &ts->signal_mask); > + > + /* > + * Set all host signal handlers. ALL signals are blocked during the > + * handlers to serialize them. > + */ > + memset(sigact_table, 0, sizeof(sigact_table)); Do you need this memset()? sigact_table is a global, so it's zero-initialized on startup, and this function is only called once. The (otherwise basically identical) Linux version of this function doesn't have it. > + > + sigfillset(&act.sa_mask); > + act.sa_sigaction = host_signal_handler; > + act.sa_flags = SA_SIGINFO; > + > + for (i = 1; i <= TARGET_NSIG; i++) { > + host_sig = target_to_host_signal(i); > + sigaction(host_sig, NULL, &oact); > + if (oact.sa_sigaction == (void *)SIG_IGN) { > + sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN; > + } else if (oact.sa_sigaction == (void *)SIG_DFL) { > + sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL; > + } > + /* > + * If there's already a handler installed then something has > + * gone horribly wrong, so don't even try to handle that case. > + * Install some handlers for our own use. We need at least > + * SIGSEGV and SIGBUS, to detect exceptions. We can not just > + * trap all signals because it affects syscall interrupt > + * behavior. But do trap all default-fatal signals. > + */ > + if (fatal_signal(i)) { > + sigaction(host_sig, &act, NULL); > + } > + } > } Otherwise Reviewed-by: Peter Maydell <peter.maydell@linaro.org> thanks -- PMM
On Thu, Jan 13, 2022 at 12:28 PM Peter Maydell <peter.maydell@linaro.org> wrote: > On Sun, 9 Jan 2022 at 16:29, Warner Losh <imp@bsdimp.com> wrote: > > > > Initialize the signal state for the emulator. Setup a set of sane > > default signal handlers, mirroring the host's signals. For fatal signals > > (those that exit by default), establish our own set of signal > > handlers. Stub out the actual signal handler we use for the moment. > > > > Signed-off-by: Stacey Son <sson@FreeBSD.org> > > Signed-off-by: Kyle Evans <kevans@freebsd.org> > > Signed-off-by: Warner Losh <imp@bsdimp.com> > > --- > > bsd-user/qemu.h | 1 + > > bsd-user/signal.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 69 insertions(+) > > > +static struct target_sigaction sigact_table[TARGET_NSIG]; > > > > > > void signal_init(void) > > { > > + TaskState *ts = (TaskState *)thread_cpu->opaque; > > + struct sigaction act; > > + struct sigaction oact; > > + int i; > > + int host_sig; > > + > > + /* Set the signal mask from the host mask. */ > > + sigprocmask(0, 0, &ts->signal_mask); > > + > > + /* > > + * Set all host signal handlers. ALL signals are blocked during the > > + * handlers to serialize them. > > + */ > > + memset(sigact_table, 0, sizeof(sigact_table)); > > Do you need this memset()? sigact_table is a global, so it's > zero-initialized on startup, and this function is only called once. > The (otherwise basically identical) Linux version of this function > doesn't have it. > Yea, that looks bogus. I'll remove it. > > + > > + sigfillset(&act.sa_mask); > > + act.sa_sigaction = host_signal_handler; > > + act.sa_flags = SA_SIGINFO; > > + > > + for (i = 1; i <= TARGET_NSIG; i++) { > > + host_sig = target_to_host_signal(i); > > + sigaction(host_sig, NULL, &oact); > > + if (oact.sa_sigaction == (void *)SIG_IGN) { > > + sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN; > > + } else if (oact.sa_sigaction == (void *)SIG_DFL) { > > + sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL; > > + } > > + /* > > + * If there's already a handler installed then something has > > + * gone horribly wrong, so don't even try to handle that case. > > + * Install some handlers for our own use. We need at least > > + * SIGSEGV and SIGBUS, to detect exceptions. We can not just > > + * trap all signals because it affects syscall interrupt > > + * behavior. But do trap all default-fatal signals. > > + */ > > + if (fatal_signal(i)) { > > + sigaction(host_sig, &act, NULL); > > + } > > + } > > } > > Otherwise > > Reviewed-by: Peter Maydell <peter.maydell@linaro.org> > thanks! Warner
On 1/10/22 3:19 AM, Warner Losh wrote: > Initialize the signal state for the emulator. Setup a set of sane > default signal handlers, mirroring the host's signals. For fatal signals > (those that exit by default), establish our own set of signal > handlers. Stub out the actual signal handler we use for the moment. > > Signed-off-by: Stacey Son <sson@FreeBSD.org> > Signed-off-by: Kyle Evans <kevans@freebsd.org> > Signed-off-by: Warner Losh <imp@bsdimp.com> > --- > bsd-user/qemu.h | 1 + > bsd-user/signal.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 69 insertions(+) > > diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h > index 334f8b1d715..0e0b8db708b 100644 > --- a/bsd-user/qemu.h > +++ b/bsd-user/qemu.h > @@ -97,6 +97,7 @@ typedef struct TaskState { > struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ > struct qemu_sigqueue *first_free; /* first free siginfo queue entry */ > int signal_pending; /* non zero if a signal may be pending */ > + sigset_t signal_mask; > > uint8_t stack[]; > } __attribute__((aligned(16))) TaskState; > diff --git a/bsd-user/signal.c b/bsd-user/signal.c > index 7ea86149981..b2c91c39379 100644 > --- a/bsd-user/signal.c > +++ b/bsd-user/signal.c > @@ -28,6 +28,9 @@ > * fork. > */ > > +static struct target_sigaction sigact_table[TARGET_NSIG]; > +static void host_signal_handler(int host_sig, siginfo_t *info, void *puc); > + > int host_to_target_signal(int sig) > { > return sig; > @@ -47,6 +50,28 @@ void queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) > qemu_log_mask(LOG_UNIMP, "No signal queueing, dropping signal %d\n", sig); > } > > +static int fatal_signal(int sig) > +{ > + > + switch (sig) { > + case TARGET_SIGCHLD: > + case TARGET_SIGURG: > + case TARGET_SIGWINCH: > + case TARGET_SIGINFO: > + /* Ignored by default. */ > + return 0; > + case TARGET_SIGCONT: > + case TARGET_SIGSTOP: > + case TARGET_SIGTSTP: > + case TARGET_SIGTTIN: > + case TARGET_SIGTTOU: > + /* Job control signals. */ > + return 0; > + default: > + return 1; > + } > +} > + > /* > * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the > * 'force' part is handled in process_pending_signals(). > @@ -64,8 +89,51 @@ void force_sig_fault(int sig, int code, abi_ulong addr) > queue_signal(env, sig, &info); > } > > +static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) > +{ > +} > + > void signal_init(void) > { > + TaskState *ts = (TaskState *)thread_cpu->opaque; > + struct sigaction act; > + struct sigaction oact; > + int i; > + int host_sig; > + > + /* Set the signal mask from the host mask. */ > + sigprocmask(0, 0, &ts->signal_mask); > + > + /* > + * Set all host signal handlers. ALL signals are blocked during the > + * handlers to serialize them. > + */ > + memset(sigact_table, 0, sizeof(sigact_table)); > + > + sigfillset(&act.sa_mask); > + act.sa_sigaction = host_signal_handler; > + act.sa_flags = SA_SIGINFO; > + > + for (i = 1; i <= TARGET_NSIG; i++) { > + host_sig = target_to_host_signal(i); > + sigaction(host_sig, NULL, &oact); Missing test for CONFIG_GPROF + SIGPROF. Otherwise, Reviewed-by: Richard Henderson <richard.henderson@linaro.org> r~
On Sun, Jan 23, 2022 at 6:38 PM Richard Henderson < richard.henderson@linaro.org> wrote: > On 1/10/22 3:19 AM, Warner Losh wrote: > > Initialize the signal state for the emulator. Setup a set of sane > > default signal handlers, mirroring the host's signals. For fatal signals > > (those that exit by default), establish our own set of signal > > handlers. Stub out the actual signal handler we use for the moment. > > > > Signed-off-by: Stacey Son <sson@FreeBSD.org> > > Signed-off-by: Kyle Evans <kevans@freebsd.org> > > Signed-off-by: Warner Losh <imp@bsdimp.com> > > --- > > bsd-user/qemu.h | 1 + > > bsd-user/signal.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 69 insertions(+) > > > > diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h > > index 334f8b1d715..0e0b8db708b 100644 > > --- a/bsd-user/qemu.h > > +++ b/bsd-user/qemu.h > > @@ -97,6 +97,7 @@ typedef struct TaskState { > > struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo > queue */ > > struct qemu_sigqueue *first_free; /* first free siginfo queue > entry */ > > int signal_pending; /* non zero if a signal may be pending */ > > + sigset_t signal_mask; > > > > uint8_t stack[]; > > } __attribute__((aligned(16))) TaskState; > > diff --git a/bsd-user/signal.c b/bsd-user/signal.c > > index 7ea86149981..b2c91c39379 100644 > > --- a/bsd-user/signal.c > > +++ b/bsd-user/signal.c > > @@ -28,6 +28,9 @@ > > * fork. > > */ > > > > +static struct target_sigaction sigact_table[TARGET_NSIG]; > > +static void host_signal_handler(int host_sig, siginfo_t *info, void > *puc); > > + > > int host_to_target_signal(int sig) > > { > > return sig; > > @@ -47,6 +50,28 @@ void queue_signal(CPUArchState *env, int sig, > target_siginfo_t *info) > > qemu_log_mask(LOG_UNIMP, "No signal queueing, dropping signal > %d\n", sig); > > } > > > > +static int fatal_signal(int sig) > > +{ > > + > > + switch (sig) { > > + case TARGET_SIGCHLD: > > + case TARGET_SIGURG: > > + case TARGET_SIGWINCH: > > + case TARGET_SIGINFO: > > + /* Ignored by default. */ > > + return 0; > > + case TARGET_SIGCONT: > > + case TARGET_SIGSTOP: > > + case TARGET_SIGTSTP: > > + case TARGET_SIGTTIN: > > + case TARGET_SIGTTOU: > > + /* Job control signals. */ > > + return 0; > > + default: > > + return 1; > > + } > > +} > > + > > /* > > * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the > > * 'force' part is handled in process_pending_signals(). > > @@ -64,8 +89,51 @@ void force_sig_fault(int sig, int code, abi_ulong > addr) > > queue_signal(env, sig, &info); > > } > > > > +static void host_signal_handler(int host_sig, siginfo_t *info, void > *puc) > > +{ > > +} > > + > > void signal_init(void) > > { > > + TaskState *ts = (TaskState *)thread_cpu->opaque; > > + struct sigaction act; > > + struct sigaction oact; > > + int i; > > + int host_sig; > > + > > + /* Set the signal mask from the host mask. */ > > + sigprocmask(0, 0, &ts->signal_mask); > > + > > + /* > > + * Set all host signal handlers. ALL signals are blocked during the > > + * handlers to serialize them. > > + */ > > + memset(sigact_table, 0, sizeof(sigact_table)); > > + > > + sigfillset(&act.sa_mask); > > + act.sa_sigaction = host_signal_handler; > > + act.sa_flags = SA_SIGINFO; > > + > > + for (i = 1; i <= TARGET_NSIG; i++) { > > + host_sig = target_to_host_signal(i); > > + sigaction(host_sig, NULL, &oact); > > Missing test for CONFIG_GPROF + SIGPROF. Otherwise, > > Reviewed-by: Richard Henderson <richard.henderson@linaro.org> > Gotcha. Will add. Warner
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 334f8b1d715..0e0b8db708b 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -97,6 +97,7 @@ typedef struct TaskState { struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ struct qemu_sigqueue *first_free; /* first free siginfo queue entry */ int signal_pending; /* non zero if a signal may be pending */ + sigset_t signal_mask; uint8_t stack[]; } __attribute__((aligned(16))) TaskState; diff --git a/bsd-user/signal.c b/bsd-user/signal.c index 7ea86149981..b2c91c39379 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -28,6 +28,9 @@ * fork. */ +static struct target_sigaction sigact_table[TARGET_NSIG]; +static void host_signal_handler(int host_sig, siginfo_t *info, void *puc); + int host_to_target_signal(int sig) { return sig; @@ -47,6 +50,28 @@ void queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) qemu_log_mask(LOG_UNIMP, "No signal queueing, dropping signal %d\n", sig); } +static int fatal_signal(int sig) +{ + + switch (sig) { + case TARGET_SIGCHLD: + case TARGET_SIGURG: + case TARGET_SIGWINCH: + case TARGET_SIGINFO: + /* Ignored by default. */ + return 0; + case TARGET_SIGCONT: + case TARGET_SIGSTOP: + case TARGET_SIGTSTP: + case TARGET_SIGTTIN: + case TARGET_SIGTTOU: + /* Job control signals. */ + return 0; + default: + return 1; + } +} + /* * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the * 'force' part is handled in process_pending_signals(). @@ -64,8 +89,51 @@ void force_sig_fault(int sig, int code, abi_ulong addr) queue_signal(env, sig, &info); } +static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) +{ +} + void signal_init(void) { + TaskState *ts = (TaskState *)thread_cpu->opaque; + struct sigaction act; + struct sigaction oact; + int i; + int host_sig; + + /* Set the signal mask from the host mask. */ + sigprocmask(0, 0, &ts->signal_mask); + + /* + * Set all host signal handlers. ALL signals are blocked during the + * handlers to serialize them. + */ + memset(sigact_table, 0, sizeof(sigact_table)); + + sigfillset(&act.sa_mask); + act.sa_sigaction = host_signal_handler; + act.sa_flags = SA_SIGINFO; + + for (i = 1; i <= TARGET_NSIG; i++) { + host_sig = target_to_host_signal(i); + sigaction(host_sig, NULL, &oact); + if (oact.sa_sigaction == (void *)SIG_IGN) { + sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN; + } else if (oact.sa_sigaction == (void *)SIG_DFL) { + sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL; + } + /* + * If there's already a handler installed then something has + * gone horribly wrong, so don't even try to handle that case. + * Install some handlers for our own use. We need at least + * SIGSEGV and SIGBUS, to detect exceptions. We can not just + * trap all signals because it affects syscall interrupt + * behavior. But do trap all default-fatal signals. + */ + if (fatal_signal(i)) { + sigaction(host_sig, &act, NULL); + } + } } void process_pending_signals(CPUArchState *cpu_env)