Error when gdb_is_target_1 is called without running gdb instance
[binutils-gdb.git] / gdb / event-top.c
index 78cbead9379e1cede76a968ba564eb06db35dc8e..8890c4fae2d50b9fa27ba56ab698550aef1103cf 100644 (file)
@@ -1,6 +1,6 @@
 /* Top level stuff for GDB, the GNU debugger.
 
-   Copyright (C) 1999-2019 Free Software Foundation, Inc.
+   Copyright (C) 1999-2022 Free Software Foundation, Inc.
 
    Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
 
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-
-/* Standard C includes.  */
-#include <signal.h>
-
-/* Local non-gdb includes.  */
-#include "annotate.h"
-#include "cli/cli-script.h"
-#include "common/buffer.h"
-#include "continuations.h"
-#include "event-loop.h"
-#include "event-top.h"
-#include "gdb_select.h"
-#include "gdbcmd.h"
-#include "gdbthread.h"
+#include "top.h"
 #include "inferior.h"
 #include "infrun.h"
+#include "target.h"
+#include "terminal.h"
+#include "gdbsupport/event-loop.h"
+#include "event-top.h"
 #include "interps.h"
+#include <signal.h>
+#include "cli/cli-script.h"     /* for reset_command_nest_depth */
 #include "main.h"
-#include "maint.h"
+#include "gdbthread.h"
 #include "observable.h"
+#include "gdbcmd.h"            /* for dont_repeat() */
+#include "annotate.h"
+#include "maint.h"
+#include "gdbsupport/buffer.h"
 #include "ser-event.h"
-#include "target.h"
-#include "terminal.h"
-#include "top.h"
+#include "gdbsupport/gdb_select.h"
+#include "gdbsupport/gdb-sigmask.h"
+#include "async-event.h"
+#include "bt-utils.h"
 
 /* readline include files.  */
 #include "readline/readline.h"
@@ -61,7 +59,6 @@ static void handle_sigquit (int sig);
 #ifdef SIGHUP
 static void handle_sighup (int sig);
 #endif
-static void handle_sigfpe (int sig);
 
 /* Functions to be invoked by the event loop in response to
    signals.  */
@@ -71,7 +68,6 @@ static void async_do_nothing (gdb_client_data);
 #ifdef SIGHUP
 static void async_disconnect (gdb_client_data);
 #endif
-static void async_float_handler (gdb_client_data);
 #ifdef SIGTSTP
 static void async_sigtstp_handler (gdb_client_data);
 #endif
@@ -90,17 +86,30 @@ static void async_sigterm_handler (gdb_client_data arg);
    ezannoni: as of 1999-04-29 I expect that this
    variable will not be used after gdb is changed to use the event
    loop as default engine, and event-top.c is merged into top.c.  */
-int set_editing_cmd_var;
+bool set_editing_cmd_var;
 
 /* This is used to display the notification of the completion of an
    asynchronous execution command.  */
-int exec_done_display_p = 0;
+bool exec_done_display_p = false;
 
 /* Used by the stdin event handler to compensate for missed stdin events.
    Setting this to a non-zero value inside an stdin callback makes the callback
    run again.  */
 int call_stdin_event_handler_again_p;
 
+/* When true GDB will produce a minimal backtrace when a fatal signal is
+   reached (within GDB code).  */
+static bool bt_on_fatal_signal = GDB_PRINT_INTERNAL_BACKTRACE_INIT_ON;
+
+/* Implement 'maintenance show backtrace-on-fatal-signal'.  */
+
+static void
+show_bt_on_fatal_signal (struct ui_file *file, int from_tty,
+                        struct cmd_list_element *cmd, const char *value)
+{
+  fprintf_filtered (file, _("Backtrace on a fatal signal is %s.\n"), value);
+}
+
 /* Signal handling variables.  */
 /* Each of these is a pointer to a function that the event loop will
    invoke if the corresponding signal has received.  The real signal
@@ -114,7 +123,6 @@ static struct async_signal_handler *sighup_token;
 #ifdef SIGQUIT
 static struct async_signal_handler *sigquit_token;
 #endif
-static struct async_signal_handler *sigfpe_token;
 #ifdef SIGTSTP
 static struct async_signal_handler *sigtstp_token;
 #endif
@@ -168,7 +176,7 @@ void (*after_char_processing_hook) (void);
 static struct gdb_exception
 gdb_rl_callback_read_char_wrapper_noexcept () noexcept
 {
-  struct gdb_exception gdb_expt = exception_none;
+  struct gdb_exception gdb_expt;
 
   /* C++ exceptions can't normally be thrown across readline (unless
      it is built with -fexceptions, but it won't by default on many
@@ -182,7 +190,7 @@ gdb_rl_callback_read_char_wrapper_noexcept () noexcept
     }
   CATCH_SJLJ (ex, RETURN_MASK_ALL)
     {
-      gdb_expt = ex;
+      gdb_expt = std::move (ex);
     }
   END_CATCH_SJLJ
 
@@ -197,7 +205,7 @@ gdb_rl_callback_read_char_wrapper (gdb_client_data client_data)
 
   /* Rethrow using the normal EH mechanism.  */
   if (gdb_expt.reason < 0)
-    throw_exception (gdb_expt);
+    throw_exception (std::move (gdb_expt));
 }
 
 /* GDB's readline callback handler.  Calls the current INPUT_HANDLER,
@@ -209,18 +217,21 @@ gdb_rl_callback_read_char_wrapper (gdb_client_data client_data)
 static void
 gdb_rl_callback_handler (char *rl) noexcept
 {
-  struct gdb_exception gdb_rl_expt = exception_none;
+  /* This is static to avoid undefined behavior when calling longjmp
+     -- gdb_exception has a destructor with side effects.  */
+  static struct gdb_exception gdb_rl_expt;
   struct ui *ui = current_ui;
 
-  TRY
+  try
     {
+      /* Ensure the exception is reset on each call.  */
+      gdb_rl_expt = {};
       ui->input_handler (gdb::unique_xmalloc_ptr<char> (rl));
     }
-  CATCH (ex, RETURN_MASK_ALL)
+  catch (gdb_exception &ex)
     {
-      gdb_rl_expt = ex;
+      gdb_rl_expt = std::move (ex);
     }
-  END_CATCH
 
   /* If we caught a GDB exception, longjmp out of the readline
      callback.  There's no other way for the callback to signal to
@@ -290,7 +301,7 @@ change_line_handler (int editing)
    is typing would lose input.  */
 
 /* Whether we've registered a callback handler with readline.  */
-static int callback_handler_installed;
+static bool callback_handler_installed;
 
 /* See event-top.h, and above.  */
 
@@ -300,7 +311,7 @@ gdb_rl_callback_handler_remove (void)
   gdb_assert (current_ui == main_ui);
 
   rl_callback_handler_remove ();
-  callback_handler_installed = 0;
+  callback_handler_installed = false;
 }
 
 /* See event-top.h, and above.  Note this wrapper doesn't have an
@@ -318,7 +329,7 @@ gdb_rl_callback_handler_install (const char *prompt)
   gdb_assert (!callback_handler_installed);
 
   rl_callback_handler_install (prompt, gdb_rl_callback_handler);
-  callback_handler_installed = 1;
+  callback_handler_installed = true;
 }
 
 /* See event-top.h, and above.  */
@@ -414,27 +425,25 @@ display_gdb_prompt (const char *new_prompt)
   else
     {
       /* Don't use a _filtered function here.  It causes the assumed
-         character position to be off, since the newline we read from
-         the user is not accounted for.  */
-      fputs_unfiltered (actual_gdb_prompt.c_str (), gdb_stdout);
+        character position to be off, since the newline we read from
+        the user is not accounted for.  */
+      printf_unfiltered ("%s", actual_gdb_prompt.c_str ());
       gdb_flush (gdb_stdout);
     }
 }
 
 /* Return the top level prompt, as specified by "set prompt", possibly
-   overriden by the python gdb.prompt_hook hook, and then composed
+   overridden by the python gdb.prompt_hook hook, and then composed
    with the prompt prefix and suffix (annotations).  */
 
 static std::string
 top_level_prompt (void)
 {
-  char *prompt;
-
   /* Give observers a chance of changing the prompt.  E.g., the python
      `gdb.prompt_hook' is installed as an observer.  */
-  gdb::observers::before_prompt.notify (get_prompt ());
+  gdb::observers::before_prompt.notify (get_prompt ().c_str ());
 
-  prompt = get_prompt ();
+  const std::string &prompt = get_prompt ();
 
   if (annotation_level >= 2)
     {
@@ -445,7 +454,7 @@ top_level_prompt (void)
         beginning.  */
       const char suffix[] = "\n\032\032prompt\n";
 
-      return std::string (prefix) + prompt + suffix;
+      return std::string (prefix) + prompt.c_str () + suffix;
     }
 
   return prompt;
@@ -485,7 +494,7 @@ stdin_event_handler (int error, gdb_client_data client_data)
       if (main_ui == ui)
        {
          /* If stdin died, we may as well kill gdb.  */
-         printf_unfiltered (_("error detected on stdin\n"));
+         fprintf_unfiltered (gdb_stderr, _("error detected on stdin\n"));
          quit_command ((char *) 0, 0);
        }
       else
@@ -523,7 +532,8 @@ stdin_event_handler (int error, gdb_client_data client_data)
 void
 ui_register_input_event_handler (struct ui *ui)
 {
-  add_file_handler (ui->input_fd, stdin_event_handler, ui);
+  add_file_handler (ui->input_fd, stdin_event_handler, ui,
+                   string_printf ("ui-%d", ui->num), true);
 }
 
 /* See top.h.  */
@@ -635,11 +645,10 @@ command_line_append_input_line (struct buffer *cmd_line_buffer, const char *rl)
    If REPEAT, handle command repetitions:
 
      - If the input command line is NOT empty, the command returned is
-       copied into the global 'saved_command_line' var so that it can
-       be repeated later.
+       saved using save_command_line () so that it can be repeated later.
 
-     - OTOH, if the input command line IS empty, return the previously
-       saved command instead of the empty input line.
+     - OTOH, if the input command line IS empty, return the saved
+       command instead of the empty input line.
 */
 
 char *
@@ -674,9 +683,9 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
   server_command = startswith (cmd, SERVER_COMMAND_PREFIX);
   if (server_command)
     {
-      /* Note that we don't set `saved_command_line'.  Between this
-         and the check in dont_repeat, this insures that repeating
-         will still do the right thing.  */
+      /* Note that we don't call `save_command_line'.  Between this
+        and the check in dont_repeat, this insures that repeating
+        will still do the right thing.  */
       return cmd + strlen (SERVER_COMMAND_PREFIX);
     }
 
@@ -714,7 +723,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
   for (p1 = cmd; *p1 == ' ' || *p1 == '\t'; p1++)
     ;
   if (repeat && *p1 == '\0')
-    return saved_command_line;
+    return get_saved_command_line ();
 
   /* Add command to history if appropriate.  Note: lines consisting
      solely of comments are also added to the command history.  This
@@ -729,9 +738,8 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
   /* Save into global buffer if appropriate.  */
   if (repeat)
     {
-      xfree (saved_command_line);
-      saved_command_line = xstrdup (cmd);
-      return saved_command_line;
+      save_command_line (cmd);
+      return get_saved_command_line ();
     }
   else
     return cmd;
@@ -788,22 +796,25 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
   int c;
   char *result;
   struct buffer line_buffer;
-  static int done_once = 0;
   struct ui *ui = current_ui;
 
   buffer_init (&line_buffer);
 
+  FILE *stream = ui->instream != nullptr ? ui->instream : ui->stdin_stream;
+  gdb_assert (stream != nullptr);
+
   /* Unbuffer the input stream, so that, later on, the calls to fgetc
      fetch only one char at the time from the stream.  The fgetc's will
      get up to the first newline, but there may be more chars in the
      stream after '\n'.  If we buffer the input and fgetc drains the
      stream, getting stuff beyond the newline as well, a select, done
-     afterwards will not trigger.  */
-  if (!done_once && !ISATTY (ui->instream))
-    {
-      setbuf (ui->instream, NULL);
-      done_once = 1;
-    }
+     afterwards will not trigger.
+
+     This unbuffering was, at one point, not applied if the input stream
+     was a tty, however, the buffering can cause problems, even for a tty,
+     in some cases.  Please ensure that any changes in this area run the MI
+     tests with the FORCE_SEPARATE_MI_TTY=1 flag being passed.  */
+  setbuf (stream, NULL);
 
   /* We still need the while loop here, even though it would seem
      obvious to invoke gdb_readline_no_editing_callback at every
@@ -816,8 +827,8 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
   while (1)
     {
       /* Read from stdin if we are executing a user defined command.
-         This is the right thing for prompt_for_continue, at least.  */
-      c = fgetc (ui->instream != NULL ? ui->instream : ui->stdin_stream);
+        This is the right thing for prompt_for_continue, at least.  */
+      c = fgetc (stream);
 
       if (c == EOF)
        {
@@ -850,73 +861,190 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
 }
 \f
 
+/* 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
+
 /* The serial event associated with the QUIT flag.  set_quit_flag sets
    this, and check_quit_flag clears it.  Used by interruptible_select
    to be able to do interruptible I/O with no race with the SIGINT
    handler.  */
 static struct serial_event *quit_serial_event;
 
-/* Initialization of signal handlers and tokens.  There is a function
-   handle_sig* for each of the signals GDB cares about.  Specifically:
-   SIGINT, SIGFPE, SIGQUIT, SIGTSTP, SIGHUP, SIGWINCH.  These
-   functions are the actual signal handlers associated to the signals
-   via calls to signal().  The only job for these functions is to
-   enqueue the appropriate event/procedure with the event loop.  Such
-   procedures are the old signal handlers.  The event loop will take
-   care of invoking the queued procedures to perform the usual tasks
-   associated with the reception of the signal.  */
-/* NOTE: 1999-04-30 This is the asynchronous version of init_signals.
-   init_signals will become obsolete as we move to have to event loop
-   as the default for gdb.  */
+/* Initialization of signal handlers and tokens.  There are a number of
+   different strategies for handling different signals here.
+
+   For SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGTSTP, there is a function
+   handle_sig* for each of these signals.  These functions are the actual
+   signal handlers associated to the signals via calls to signal().  The
+   only job for these functions is to enqueue the appropriate
+   event/procedure with the event loop.  The event loop will take care of
+   invoking the queued procedures to perform the usual tasks associated
+   with the reception of the signal.
+
+   For SIGSEGV the handle_sig* function does all the work for handling this
+   signal.
+
+   For SIGFPE, SIGBUS, and SIGABRT, these signals will all cause GDB to
+   terminate immediately.  */
 void
-async_init_signals (void)
+gdb_init_signals (void)
 {
   initialize_async_signal_handlers ();
 
   quit_serial_event = make_serial_event ();
 
-  signal (SIGINT, handle_sigint);
   sigint_token =
-    create_async_signal_handler (async_request_quit, NULL);
-  signal (SIGTERM, handle_sigterm);
-  async_sigterm_token
-    = create_async_signal_handler (async_sigterm_handler, NULL);
+    create_async_signal_handler (async_request_quit, NULL, "sigint");
+  signal (SIGINT, handle_sigint);
 
-  /* If SIGTRAP was set to SIG_IGN, then the SIG_IGN will get passed
-     to the inferior and breakpoints will be ignored.  */
-#ifdef SIGTRAP
-  signal (SIGTRAP, SIG_DFL);
-#endif
+  async_sigterm_token
+    = create_async_signal_handler (async_sigterm_handler, NULL, "sigterm");
+  signal (SIGTERM, handle_sigterm);
 
 #ifdef SIGQUIT
-  /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get
-     passed to the inferior, which we don't want.  It would be
-     possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but
-     on BSD4.3 systems using vfork, that can affect the
-     GDB process as well as the inferior (the signal handling tables
-     might be in memory, shared between the two).  Since we establish
-     a handler for SIGQUIT, when we call exec it will set the signal
-     to SIG_DFL for us.  */
-  signal (SIGQUIT, handle_sigquit);
   sigquit_token =
-    create_async_signal_handler (async_do_nothing, NULL);
+    create_async_signal_handler (async_do_nothing, NULL, "sigquit");
+  signal (SIGQUIT, handle_sigquit);
 #endif
+
 #ifdef SIGHUP
   if (signal (SIGHUP, handle_sighup) != SIG_IGN)
     sighup_token =
-      create_async_signal_handler (async_disconnect, NULL);
+      create_async_signal_handler (async_disconnect, NULL, "sighup");
   else
     sighup_token =
-      create_async_signal_handler (async_do_nothing, NULL);
+      create_async_signal_handler (async_do_nothing, NULL, "sighup");
 #endif
-  signal (SIGFPE, handle_sigfpe);
-  sigfpe_token =
-    create_async_signal_handler (async_float_handler, NULL);
 
 #ifdef SIGTSTP
   sigtstp_token =
-    create_async_signal_handler (async_sigtstp_handler, NULL);
+    create_async_signal_handler (async_sigtstp_handler, NULL, "sigtstp");
+#endif
+
+#ifdef SIGFPE
+  signal (SIGFPE, handle_fatal_signal);
+#endif
+
+#ifdef SIGBUS
+  signal (SIGBUS, handle_fatal_signal);
+#endif
+
+#ifdef SIGABRT
+  signal (SIGABRT, handle_fatal_signal);
 #endif
+
+  install_handle_sigsegv ();
 }
 
 /* See defs.h.  */
@@ -1086,27 +1214,29 @@ static void
 async_disconnect (gdb_client_data arg)
 {
 
-  TRY
+  try
     {
       quit_cover ();
     }
 
-  CATCH (exception, RETURN_MASK_ALL)
+  catch (const gdb_exception &exception)
     {
       fputs_filtered ("Could not kill the program being debugged",
                      gdb_stderr);
       exception_print (gdb_stderr, exception);
     }
-  END_CATCH
 
-  TRY
-    {
-      pop_all_targets ();
-    }
-  CATCH (exception, RETURN_MASK_ALL)
+  for (inferior *inf : all_inferiors ())
     {
+      switch_to_inferior_no_thread (inf);
+      try
+       {
+         pop_all_targets ();
+       }
+      catch (const gdb_exception &exception)
+       {
+       }
     }
-  END_CATCH
 
   signal (SIGHUP, SIG_DFL);    /*FIXME: ???????????  */
   raise (SIGHUP);
@@ -1124,22 +1254,13 @@ handle_sigtstp (int sig)
 static void
 async_sigtstp_handler (gdb_client_data arg)
 {
-  char *prompt = get_prompt ();
+  const std::string &prompt = get_prompt ();
 
   signal (SIGTSTP, SIG_DFL);
-#if HAVE_SIGPROCMASK
-  {
-    sigset_t zero;
-
-    sigemptyset (&zero);
-    sigprocmask (SIG_SETMASK, &zero, 0);
-  }
-#elif HAVE_SIGSETMASK
-  sigsetmask (0);
-#endif
+  unblock_signal (SIGTSTP);
   raise (SIGTSTP);
   signal (SIGTSTP, handle_sigtstp);
-  printf_unfiltered ("%s", prompt);
+  printf_unfiltered ("%s", prompt.c_str ());
   gdb_flush (gdb_stdout);
 
   /* Forget about any previous command -- null line now will do
@@ -1148,23 +1269,6 @@ async_sigtstp_handler (gdb_client_data arg)
 }
 #endif /* SIGTSTP */
 
-/* Tell the event loop what to do if SIGFPE is received.
-   See event-signal.c.  */
-static void
-handle_sigfpe (int sig)
-{
-  mark_async_signal_handler (sigfpe_token);
-  signal (sig, handle_sigfpe);
-}
-
-/* Event loop will call this functin to process a SIGFPE.  */
-static void
-async_float_handler (gdb_client_data arg)
-{
-  /* This message is based on ANSI C, section 4.7.  Note that integer
-     divide by zero causes this, so "float" is a misnomer.  */
-  error (_("Erroneous arithmetic operation."));
-}
 \f
 
 /* Set things up for readline to be invoked via the alternate
@@ -1244,3 +1348,77 @@ gdb_disable_readline (void)
     gdb_rl_callback_handler_remove ();
   delete_file_handler (ui->input_fd);
 }
+
+scoped_segv_handler_restore::scoped_segv_handler_restore (segv_handler_t new_handler)
+{
+  m_old_handler = thread_local_segv_handler;
+  thread_local_segv_handler = new_handler;
+}
+
+scoped_segv_handler_restore::~scoped_segv_handler_restore()
+{
+  thread_local_segv_handler = m_old_handler;
+}
+
+static const char debug_event_loop_off[] = "off";
+static const char debug_event_loop_all_except_ui[] = "all-except-ui";
+static const char debug_event_loop_all[] = "all";
+
+static const char *debug_event_loop_enum[] = {
+  debug_event_loop_off,
+  debug_event_loop_all_except_ui,
+  debug_event_loop_all,
+  nullptr
+};
+
+static const char *debug_event_loop_value = debug_event_loop_off;
+
+static void
+set_debug_event_loop_command (const char *args, int from_tty,
+                             cmd_list_element *c)
+{
+  if (debug_event_loop_value == debug_event_loop_off)
+    debug_event_loop = debug_event_loop_kind::OFF;
+  else if (debug_event_loop_value == debug_event_loop_all_except_ui)
+    debug_event_loop = debug_event_loop_kind::ALL_EXCEPT_UI;
+  else if (debug_event_loop_value == debug_event_loop_all)
+    debug_event_loop = debug_event_loop_kind::ALL;
+  else
+    gdb_assert_not_reached ("Invalid debug event look kind value.");
+}
+
+static void
+show_debug_event_loop_command (struct ui_file *file, int from_tty,
+                              struct cmd_list_element *cmd, const char *value)
+{
+  fprintf_filtered (file, _("Event loop debugging is %s.\n"), value);
+}
+
+void _initialize_event_top ();
+void
+_initialize_event_top ()
+{
+  add_setshow_enum_cmd ("event-loop", class_maintenance,
+                       debug_event_loop_enum,
+                       &debug_event_loop_value,
+                       _("Set event-loop debugging."),
+                       _("Show event-loop debugging."),
+                       _("\
+Control whether to show event loop-related debug messages."),
+                       set_debug_event_loop_command,
+                       show_debug_event_loop_command,
+                       &setdebuglist, &showdebuglist);
+
+  add_setshow_boolean_cmd ("backtrace-on-fatal-signal", class_maintenance,
+                          &bt_on_fatal_signal, _("\
+Set whether to produce a backtrace if GDB receives a fatal signal."), _("\
+Show whether GDB will produce a backtrace if it receives a fatal signal."), _("\
+Use \"on\" to enable, \"off\" to disable.\n\
+If enabled, GDB will produce a minimal backtrace if it encounters a fatal\n\
+signal from within GDB itself.  This is a mechanism to help diagnose\n\
+crashes within GDB, not a mechanism for debugging inferiors."),
+                          gdb_internal_backtrace_set_cmd,
+                          show_bt_on_fatal_signal,
+                          &maintenance_set_cmdlist,
+                          &maintenance_show_cmdlist);
+}