aboutsummaryrefslogtreecommitdiff
path: root/bsd-user
diff options
context:
space:
mode:
authorWarner Losh <imp@bsdimp.com>2022-01-08 21:05:20 -0700
committerWarner Losh <imp@bsdimp.com>2022-01-28 15:53:41 -0700
commit377145478339917491a850643bb920548907d956 (patch)
tree9980c1848726f4d1781a954b8d58c7a31eca3266 /bsd-user
parentfd5bec9ad28eaa454feaad46e68a76b9eeedb3ff (diff)
bsd-user/signal.c: Implement dump_core_and_abort
Force delivering a signal and generating a core file. It's a global function 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> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'bsd-user')
-rw-r--r--bsd-user/signal.c76
-rw-r--r--bsd-user/syscall_defs.h1
2 files changed, 77 insertions, 0 deletions
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index 24cf4b1120..ccda7adbee 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -172,6 +172,82 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
tinfo->si_code = deposit32(si_code, 24, 8, si_type);
}
+/* Returns 1 if given signal should dump core if not handled. */
+static int core_dump_signal(int sig)
+{
+ switch (sig) {
+ case TARGET_SIGABRT:
+ case TARGET_SIGFPE:
+ case TARGET_SIGILL:
+ case TARGET_SIGQUIT:
+ case TARGET_SIGSEGV:
+ case TARGET_SIGTRAP:
+ case TARGET_SIGBUS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Abort execution with signal. */
+static void QEMU_NORETURN dump_core_and_abort(int target_sig)
+{
+ 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 04a1a886d7..62b472b990 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"