+/* Attempt to unblock signal SIG, return true if the signal was unblocked,
+ otherwise, return false. */
+
+static bool
+unblock_signal (int sig)
+{
+#if HAVE_SIGPROCMASK
+ sigset_t sigset;
+ sigemptyset (&sigset);
+ sigaddset (&sigset, sig);
+ gdb_sigmask (SIG_UNBLOCK, &sigset, 0);
+ return true;
+#endif
+
+ return false;
+}
+
+/* Called to handle fatal signals. SIG is the signal number. */
+
+static void ATTRIBUTE_NORETURN
+handle_fatal_signal (int sig)
+{
+#ifdef GDB_PRINT_INTERNAL_BACKTRACE
+ const auto sig_write = [] (const char *msg) -> void
+ {
+ gdb_stderr->write_async_safe (msg, strlen (msg));
+ };
+
+ if (bt_on_fatal_signal)
+ {
+ sig_write ("\n\n");
+ sig_write (_("Fatal signal: "));
+ sig_write (strsignal (sig));
+ sig_write ("\n");
+
+ gdb_internal_backtrace ();
+
+ sig_write (_("A fatal error internal to GDB has been detected, "
+ "further\ndebugging is not possible. GDB will now "
+ "terminate.\n\n"));
+ sig_write (_("This is a bug, please report it."));
+ if (REPORT_BUGS_TO[0] != '\0')
+ {
+ sig_write (_(" For instructions, see:\n"));
+ sig_write (REPORT_BUGS_TO);
+ sig_write (".");
+ }
+ sig_write ("\n\n");
+
+ gdb_stderr->flush ();
+ }
+#endif
+
+ /* If possible arrange for SIG to have its default behaviour (which
+ should be to terminate the current process), unblock SIG, and reraise
+ the signal. This ensures GDB terminates with the expected signal. */
+ if (signal (sig, SIG_DFL) != SIG_ERR
+ && unblock_signal (sig))
+ raise (sig);
+
+ /* The above failed, so try to use SIGABRT to terminate GDB. */
+#ifdef SIGABRT
+ signal (SIGABRT, SIG_DFL);
+#endif
+ abort (); /* ARI: abort */
+}
+
+/* The SIGSEGV handler for this thread, or NULL if there is none. GDB
+ always installs a global SIGSEGV handler, and then lets threads
+ indicate their interest in handling the signal by setting this
+ thread-local variable.
+
+ This is a static variable instead of extern because on various platforms
+ (notably Cygwin) extern thread_local variables cause link errors. So
+ instead, we have scoped_segv_handler_restore, which also makes it impossible
+ to accidentally forget to restore it to the original value. */
+
+static thread_local void (*thread_local_segv_handler) (int);
+
+static void handle_sigsegv (int sig);
+
+/* Install the SIGSEGV handler. */
+static void
+install_handle_sigsegv ()
+{
+#if defined (HAVE_SIGACTION)
+ struct sigaction sa;
+ sa.sa_handler = handle_sigsegv;
+ sigemptyset (&sa.sa_mask);
+#ifdef HAVE_SIGALTSTACK
+ sa.sa_flags = SA_ONSTACK;
+#else
+ sa.sa_flags = 0;
+#endif
+ sigaction (SIGSEGV, &sa, nullptr);
+#else
+ signal (SIGSEGV, handle_sigsegv);
+#endif
+}
+
+/* Handler for SIGSEGV. */
+
+static void
+handle_sigsegv (int sig)
+{
+ install_handle_sigsegv ();
+
+ if (thread_local_segv_handler == nullptr)
+ handle_fatal_signal (sig);
+ thread_local_segv_handler (sig);
+}
+
+\f
+