gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / event-top.c
index 54fe471f2c03686c0680ce35a25550b5313e266d..ac0f3701016e19450f516ad510b20cc26d57b758 100644 (file)
@@ -1,6 +1,6 @@
 /* Top level stuff for GDB, the GNU debugger.
 
-   Copyright (C) 1999-2017 Free Software Foundation, Inc.
+   Copyright (C) 1999-2020 Free Software Foundation, Inc.
 
    Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
 
 #include "inferior.h"
 #include "infrun.h"
 #include "target.h"
-#include "terminal.h"          /* for job_control */
-#include "event-loop.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 "gdbthread.h"
-#include "observer.h"
+#include "observable.h"
 #include "continuations.h"
 #include "gdbcmd.h"            /* for dont_repeat() */
 #include "annotate.h"
 #include "maint.h"
-#include "buffer.h"
+#include "gdbsupport/buffer.h"
 #include "ser-event.h"
-#include "gdb_select.h"
+#include "gdbsupport/gdb_select.h"
+#include "gdbsupport/gdb-sigmask.h"
+#include "async-event.h"
 
 /* readline include files.  */
 #include "readline/readline.h"
@@ -68,8 +70,8 @@ static void async_do_nothing (gdb_client_data);
 static void async_disconnect (gdb_client_data);
 #endif
 static void async_float_handler (gdb_client_data);
-#ifdef STOP_SIGNAL
-static void async_stop_sig (gdb_client_data);
+#ifdef SIGTSTP
+static void async_sigtstp_handler (gdb_client_data);
 #endif
 static void async_sigterm_handler (gdb_client_data arg);
 
@@ -86,11 +88,11 @@ 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
@@ -111,7 +113,7 @@ static struct async_signal_handler *sighup_token;
 static struct async_signal_handler *sigquit_token;
 #endif
 static struct async_signal_handler *sigfpe_token;
-#ifdef STOP_SIGNAL
+#ifdef SIGTSTP
 static struct async_signal_handler *sigtstp_token;
 #endif
 static struct async_signal_handler *async_sigterm_token;
@@ -164,7 +166,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
@@ -178,7 +180,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
 
@@ -193,7 +195,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,
@@ -205,18 +207,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
     {
-      ui->input_handler (rl);
+      /* 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
@@ -412,13 +417,13 @@ display_gdb_prompt (const char *new_prompt)
       /* 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);
+      fprintf_unfiltered (gdb_stdout, "%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
@@ -428,7 +433,7 @@ top_level_prompt (void)
 
   /* Give observers a chance of changing the prompt.  E.g., the python
      `gdb.prompt_hook' is installed as an observer.  */
-  observer_notify_before_prompt (get_prompt ());
+  gdb::observers::before_prompt.notify (get_prompt ());
 
   prompt = get_prompt ();
 
@@ -487,7 +492,7 @@ stdin_event_handler (int error, gdb_client_data client_data)
       else
        {
          /* Simply delete the UI.  */
-         delete_ui (ui);
+         delete ui;
        }
     }
   else
@@ -565,10 +570,10 @@ async_disable_stdin (void)
    a whole command.  */
 
 void
-command_handler (char *command)
+command_handler (const char *command)
 {
   struct ui *ui = current_ui;
-  char *c;
+  const char *c;
 
   if (ui->instream == ui->stdin_stream)
     reinitialize_more_filter ();
@@ -591,10 +596,10 @@ command_handler (char *command)
    emulations, to CMD_LINE_BUFFER.  Returns the command line if we
    have a whole command line ready to be processed by the command
    interpreter or NULL if the command line isn't complete yet (input
-   line ends in a backslash).  Takes ownership of RL.  */
+   line ends in a backslash).  */
 
 static char *
-command_line_append_input_line (struct buffer *cmd_line_buffer, char *rl)
+command_line_append_input_line (struct buffer *cmd_line_buffer, const char *rl)
 {
   char *cmd;
   size_t len;
@@ -615,9 +620,6 @@ command_line_append_input_line (struct buffer *cmd_line_buffer, char *rl)
       cmd = cmd_line_buffer->buffer;
     }
 
-  /* Allocated in readline.  */
-  xfree (rl);
-
   return cmd;
 }
 
@@ -634,16 +636,16 @@ command_line_append_input_line (struct buffer *cmd_line_buffer, 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 *
 handle_line_of_input (struct buffer *cmd_line_buffer,
-                     char *rl, int repeat, const char *annotation_suffix)
+                     const char *rl, int repeat,
+                     const char *annotation_suffix)
 {
   struct ui *ui = current_ui;
   int from_tty = ui->instream == ui->stdin_stream;
@@ -669,9 +671,10 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
     }
 
 #define SERVER_COMMAND_PREFIX "server "
-  if (startswith (cmd, SERVER_COMMAND_PREFIX))
+  server_command = startswith (cmd, SERVER_COMMAND_PREFIX);
+  if (server_command)
     {
-      /* Note that we don't set `saved_command_line'.  Between this
+      /* 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);
@@ -680,31 +683,29 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
   /* Do history expansion if that is wished.  */
   if (history_expansion_p && from_tty && input_interactive_p (current_ui))
     {
-      char *history_value;
+      char *cmd_expansion;
       int expanded;
 
-      expanded = history_expand (cmd, &history_value);
+      expanded = history_expand (cmd, &cmd_expansion);
+      gdb::unique_xmalloc_ptr<char> history_value (cmd_expansion);
       if (expanded)
        {
          size_t len;
 
          /* Print the changes.  */
-         printf_unfiltered ("%s\n", history_value);
+         printf_unfiltered ("%s\n", history_value.get ());
 
          /* If there was an error, call this function again.  */
          if (expanded < 0)
-           {
-             xfree (history_value);
-             return cmd;
-           }
+           return cmd;
 
          /* history_expand returns an allocated string.  Just replace
             our buffer with it.  */
-         len = strlen (history_value);
+         len = strlen (history_value.get ());
          xfree (buffer_finish (cmd_line_buffer));
-         cmd_line_buffer->buffer = history_value;
+         cmd_line_buffer->buffer = history_value.get ();
          cmd_line_buffer->buffer_size = len + 1;
-         cmd = history_value;
+         cmd = history_value.release ();
        }
     }
 
@@ -713,7 +714,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
@@ -728,9 +729,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;
@@ -745,13 +745,13 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
    function.  */
 
 void
-command_line_handler (char *rl)
+command_line_handler (gdb::unique_xmalloc_ptr<char> &&rl)
 {
   struct buffer *line_buffer = get_command_line_buffer ();
   struct ui *ui = current_ui;
   char *cmd;
 
-  cmd = handle_line_of_input (line_buffer, rl, 1, "prompt");
+  cmd = handle_line_of_input (line_buffer, rl.get (), 1, "prompt");
   if (cmd == (char *) EOF)
     {
       /* stdin closed.  The connection with the terminal is gone.
@@ -759,7 +759,7 @@ command_line_handler (char *rl)
         hung up but GDB is still alive.  In such a case, we just quit
         gdb killing the inferior program too.  */
       printf_unfiltered ("quit\n");
-      execute_command ((char *) "quit", 1);
+      execute_command ("quit", 1);
     }
   else if (cmd == NULL)
     {
@@ -845,10 +845,49 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
 
   buffer_grow_char (&line_buffer, '\0');
   result = buffer_finish (&line_buffer);
-  ui->input_handler (result);
+  ui->input_handler (gdb::unique_xmalloc_ptr<char> (result));
 }
 \f
 
+/* See event-top.h.  */
+
+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)
+    abort ();                  /* ARI: abort */
+  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
@@ -912,10 +951,12 @@ async_init_signals (void)
   sigfpe_token =
     create_async_signal_handler (async_float_handler, NULL);
 
-#ifdef STOP_SIGNAL
+#ifdef SIGTSTP
   sigtstp_token =
-    create_async_signal_handler (async_stop_sig, NULL);
+    create_async_signal_handler (async_sigtstp_handler, NULL);
 #endif
+
+  install_handle_sigsegv ();
 }
 
 /* See defs.h.  */
@@ -1085,63 +1126,61 @@ 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);
 }
 #endif
 
-#ifdef STOP_SIGNAL
+#ifdef SIGTSTP
 void
-handle_stop_sig (int sig)
+handle_sigtstp (int sig)
 {
   mark_async_signal_handler (sigtstp_token);
-  signal (sig, handle_stop_sig);
+  signal (sig, handle_sigtstp);
 }
 
 static void
-async_stop_sig (gdb_client_data arg)
+async_sigtstp_handler (gdb_client_data arg)
 {
   char *prompt = get_prompt ();
 
-#if STOP_SIGNAL == SIGTSTP
   signal (SIGTSTP, SIG_DFL);
 #if HAVE_SIGPROCMASK
   {
     sigset_t zero;
 
     sigemptyset (&zero);
-    sigprocmask (SIG_SETMASK, &zero, 0);
+    gdb_sigmask (SIG_SETMASK, &zero, 0);
   }
 #elif HAVE_SIGSETMASK
   sigsetmask (0);
 #endif
   raise (SIGTSTP);
-  signal (SIGTSTP, handle_stop_sig);
-#else
-  signal (STOP_SIGNAL, handle_stop_sig);
-#endif
+  signal (SIGTSTP, handle_sigtstp);
   printf_unfiltered ("%s", prompt);
   gdb_flush (gdb_stdout);
 
@@ -1149,7 +1188,7 @@ async_stop_sig (gdb_client_data arg)
      nothing.  */
   dont_repeat ();
 }
-#endif /* STOP_SIGNAL */
+#endif /* SIGTSTP */
 
 /* Tell the event loop what to do if SIGFPE is received.
    See event-signal.c.  */
@@ -1160,7 +1199,7 @@ handle_sigfpe (int sig)
   signal (sig, handle_sigfpe);
 }
 
-/* Event loop will call this functin to process a SIGFPE.  */
+/* Event loop will call this function to process a SIGFPE.  */
 static void
 async_float_handler (gdb_client_data arg)
 {
This page took 0.029608 seconds and 4 git commands to generate.