On Sun, 9 Jan 2022 at 16:44, Warner Losh <i...@bsdimp.com> wrote:
>
> Force delivering a signal and generating a core file.
>
> Signed-off-by: Stacey Son <s...@freebsd.org>
> Signed-off-by: Kyle Evans <kev...@freebsd.org>
> Signed-off-by: Warner Losh <i...@bsdimp.com>
> ---
>  bsd-user/qemu.h         |  1 +
>  bsd-user/signal.c       | 59 +++++++++++++++++++++++++++++++++++++++++
>  bsd-user/syscall_defs.h |  1 +
>  3 files changed, 61 insertions(+)
>
> diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
> index 7c54a933eb8..e12617f5d69 100644
> --- a/bsd-user/qemu.h
> +++ b/bsd-user/qemu.h
> @@ -223,6 +223,7 @@ void queue_signal(CPUArchState *env, int sig, 
> target_siginfo_t *info);
>  abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong 
> sp);
>  int target_to_host_signal(int sig);
>  int host_to_target_signal(int sig);
> +void QEMU_NORETURN force_sig(int target_sig);
>
>  /* mmap.c */
>  int target_mprotect(abi_ulong start, abi_ulong len, int prot);
> diff --git a/bsd-user/signal.c b/bsd-user/signal.c
> index 824535be8b8..97f42f9c45e 100644
> --- a/bsd-user/signal.c
> +++ b/bsd-user/signal.c
> @@ -109,6 +109,65 @@ static int core_dump_signal(int sig)
>      }
>  }
>
> +/* Abort execution with signal. */
> +void QEMU_NORETURN force_sig(int target_sig)

In linux-user we call this dump_core_and_abort(), which is
a name that better describes what it's actually doing.

(Today's linux-user's force_sig() does what the Linux kernel's
function of that name does -- it's a wrapper around
queue_signal() which delivers a signal to the guest with
.si_code = SI_KERNEL , si_pid = si_uid = 0.
Whether you want one of those or not depends on what BSD
kernels do in that kind of "we have to kill this process"
situation.)

> +{
> +    CPUArchState *env = thread_cpu->env_ptr;
> +    CPUState *cpu = env_cpu(env);
> +    TaskState *ts = cpu->opaque;
> +    int core_dumped = 0;
> +    int host_sig;
> +    struct sigaction act;
> +
> +    host_sig = target_to_host_signal(target_sig);
> +    gdb_signalled(env, target_sig);
> +
> +    /* Dump core if supported by target binary format */
> +    if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
> +        stop_all_tasks();
> +        core_dumped =
> +            ((*ts->bprm->core_dump)(target_sig, env) == 0);
> +    }
> +    if (core_dumped) {
> +        struct rlimit nodump;
> +
> +        /*
> +         * We already dumped the core of target process, we don't want
> +         * a coredump of qemu itself.
> +         */
> +         getrlimit(RLIMIT_CORE, &nodump);
> +         nodump.rlim_cur = 0;
> +         setrlimit(RLIMIT_CORE, &nodump);
> +         (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) "
> +             "- %s\n", target_sig, strsignal(host_sig), "core dumped");
> +    }
> +
> +    /*
> +     * 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.
> +     */
> +    memset(&act, 0, sizeof(act));
> +    sigfillset(&act.sa_mask);
> +    act.sa_handler = SIG_DFL;
> +    sigaction(host_sig, &act, NULL);
> +
> +    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();
> +}
> +
>  /*
>   * Queue a signal so that it will be send to the virtual CPU as soon as
>   * possible.
> diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
> index 04a1a886d7b..62b472b990b 100644
> --- a/bsd-user/syscall_defs.h
> +++ b/bsd-user/syscall_defs.h
> @@ -21,6 +21,7 @@
>  #define _SYSCALL_DEFS_H_
>
>  #include <sys/syscall.h>
> +#include <sys/resource.h>
>
>  #include "errno_defs.h"
>

-- PMM

Reply via email to