Remove useless assignment from tui_remove_hooks
[external/binutils.git] / gdb / record-full.c
index 58f4be4..e83ce01 100644 (file)
@@ -1,6 +1,6 @@
 /* Process record and replay target for GDB, the GNU debugger.
 
-   Copyright (C) 2013-2018 Free Software Foundation, Inc.
+   Copyright (C) 2013-2019 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -21,6 +21,7 @@
 #include "gdbcmd.h"
 #include "regcache.h"
 #include "gdbthread.h"
+#include "inferior.h"
 #include "event-top.h"
 #include "completer.h"
 #include "arch-utils.h"
@@ -35,8 +36,8 @@
 #include "gdb_bfd.h"
 #include "observable.h"
 #include "infrun.h"
-#include "common/gdb_unlinker.h"
-#include "common/byte-vector.h"
+#include "gdbsupport/gdb_unlinker.h"
+#include "gdbsupport/byte-vector.h"
 
 #include <signal.h>
 
@@ -206,24 +207,21 @@ static unsigned int record_full_insn_num = 0;
    than count of insns presently in execution log).  */
 static ULONGEST record_full_insn_count;
 
+static const char record_longname[]
+  = N_("Process record and replay target");
+static const char record_doc[]
+  = N_("Log program while executing and replay execution from log.");
+
 /* Base class implementing functionality common to both the
    "record-full" and "record-core" targets.  */
 
 class record_full_base_target : public target_ops
 {
 public:
-  record_full_base_target ()
-  { to_stratum = record_stratum; }
-
-  const char *shortname () override = 0;
-
-  const char *longname () override
-  { return _("Process record and replay target"); }
+  const target_info &info () const override = 0;
 
-  const char *doc () override
-  { return _("Log program while executing and replay execution from log."); }
+  strata stratum () const override { return record_stratum; }
 
-  void open (const char *, int) override;
   void close () override;
   void async (int) override;
   ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
@@ -257,11 +255,17 @@ public:
 
 /* The "record-full" target.  */
 
+static const target_info record_full_target_info = {
+  "record-full",
+  record_longname,
+  record_doc,
+};
+
 class record_full_target final : public record_full_base_target
 {
 public:
-  const char *shortname () override
-  { return "record-full"; }
+  const target_info &info () const override
+  { return record_full_target_info; }
 
   void commit_resume () override;
   void resume (ptid_t, int, enum gdb_signal) override;
@@ -285,11 +289,17 @@ public:
 
 /* The "record-core" target.  */
 
+static const target_info record_full_core_target_info = {
+  "record-core",
+  record_longname,
+  record_doc,
+};
+
 class record_full_core_target final : public record_full_base_target
 {
 public:
-  const char *shortname () override
-  { return "record-core"; }
+  const target_info &info () const override
+  { return record_full_core_target_info; }
 
   void resume (ptid_t, int, enum gdb_signal) override;
   void disconnect (const char *, int) override;
@@ -610,7 +620,7 @@ record_full_arch_list_add_reg (struct regcache *regcache, int regnum)
 
   rec = record_full_reg_alloc (regcache, regnum);
 
-  regcache_raw_read (regcache, regnum, record_full_get_loc (rec));
+  regcache->raw_read (regnum, record_full_get_loc (rec));
 
   record_full_arch_list_add (rec);
 
@@ -686,12 +696,6 @@ record_full_check_insn_num (void)
     }
 }
 
-static void
-record_full_arch_list_cleanups (void *ignore)
-{
-  record_full_list_release (record_full_arch_list_tail);
-}
-
 /* Before inferior step (when GDB record the running message, inferior
    only can step), GDB will call this function to record the values to
    record_full_list.  This function will call gdbarch_process_record to
@@ -703,61 +707,66 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal)
 {
   int ret;
   struct gdbarch *gdbarch = regcache->arch ();
-  struct cleanup *old_cleanups
-    = make_cleanup (record_full_arch_list_cleanups, 0);
 
-  record_full_arch_list_head = NULL;
-  record_full_arch_list_tail = NULL;
+  try
+    {
+      record_full_arch_list_head = NULL;
+      record_full_arch_list_tail = NULL;
 
-  /* Check record_full_insn_num.  */
-  record_full_check_insn_num ();
+      /* Check record_full_insn_num.  */
+      record_full_check_insn_num ();
+
+      /* If gdb sends a signal value to target_resume,
+        save it in the 'end' field of the previous instruction.
 
-  /* If gdb sends a signal value to target_resume,
-     save it in the 'end' field of the previous instruction.
+        Maybe process record should record what really happened,
+        rather than what gdb pretends has happened.
 
-     Maybe process record should record what really happened,
-     rather than what gdb pretends has happened.
+        So if Linux delivered the signal to the child process during
+        the record mode, we will record it and deliver it again in
+        the replay mode.
 
-     So if Linux delivered the signal to the child process during
-     the record mode, we will record it and deliver it again in
-     the replay mode.
+        If user says "ignore this signal" during the record mode, then
+        it will be ignored again during the replay mode (no matter if
+        the user says something different, like "deliver this signal"
+        during the replay mode).
 
-     If user says "ignore this signal" during the record mode, then
-     it will be ignored again during the replay mode (no matter if
-     the user says something different, like "deliver this signal"
-     during the replay mode).
+        User should understand that nothing he does during the replay
+        mode will change the behavior of the child.  If he tries,
+        then that is a user error.
 
-     User should understand that nothing he does during the replay
-     mode will change the behavior of the child.  If he tries,
-     then that is a user error.
+        But we should still deliver the signal to gdb during the replay,
+        if we delivered it during the recording.  Therefore we should
+        record the signal during record_full_wait, not
+        record_full_resume.  */
+      if (record_full_list != &record_full_first)  /* FIXME better way
+                                                     to check */
+       {
+         gdb_assert (record_full_list->type == record_full_end);
+         record_full_list->u.end.sigval = signal;
+       }
 
-     But we should still deliver the signal to gdb during the replay,
-     if we delivered it during the recording.  Therefore we should
-     record the signal during record_full_wait, not
-     record_full_resume.  */
-  if (record_full_list != &record_full_first)  /* FIXME better way to check */
+      if (signal == GDB_SIGNAL_0
+         || !gdbarch_process_record_signal_p (gdbarch))
+       ret = gdbarch_process_record (gdbarch,
+                                     regcache,
+                                     regcache_read_pc (regcache));
+      else
+       ret = gdbarch_process_record_signal (gdbarch,
+                                            regcache,
+                                            signal);
+
+      if (ret > 0)
+       error (_("Process record: inferior program stopped."));
+      if (ret < 0)
+       error (_("Process record: failed to record execution log."));
+    }
+  catch (const gdb_exception &ex)
     {
-      gdb_assert (record_full_list->type == record_full_end);
-      record_full_list->u.end.sigval = signal;
+      record_full_list_release (record_full_arch_list_tail);
+      throw;
     }
 
-  if (signal == GDB_SIGNAL_0
-      || !gdbarch_process_record_signal_p (gdbarch))
-    ret = gdbarch_process_record (gdbarch,
-                                 regcache,
-                                 regcache_read_pc (regcache));
-  else
-    ret = gdbarch_process_record_signal (gdbarch,
-                                        regcache,
-                                        signal);
-
-  if (ret > 0)
-    error (_("Process record: inferior program stopped."));
-  if (ret < 0)
-    error (_("Process record: failed to record execution log."));
-
-  discard_cleanups (old_cleanups);
-
   record_full_list->next = record_full_arch_list_head;
   record_full_arch_list_head->prev = record_full_list;
   record_full_list = record_full_arch_list_tail;
@@ -772,16 +781,15 @@ static bool
 record_full_message_wrapper_safe (struct regcache *regcache,
                                  enum gdb_signal signal)
 {
-  TRY
+  try
     {
       record_full_message (regcache, signal);
     }
-  CATCH (ex, RETURN_MASK_ALL)
+  catch (const gdb_exception &ex)
     {
       exception_print (gdb_stderr, ex);
       return false;
     }
-  END_CATCH
 
   return true;
 }
@@ -823,9 +831,8 @@ record_full_exec_insn (struct regcache *regcache,
                               host_address_to_string (entry),
                               entry->u.reg.num);
 
-        regcache_cooked_read (regcache, entry->u.reg.num, reg.data ());
-        regcache_cooked_write (regcache, entry->u.reg.num, 
-                              record_full_get_loc (entry));
+        regcache->cooked_read (entry->u.reg.num, reg.data ());
+        regcache->cooked_write (entry->u.reg.num, record_full_get_loc (entry));
         memcpy (record_full_get_loc (entry), reg.data (), entry->u.reg.len);
       }
       break;
@@ -900,7 +907,7 @@ record_full_async_inferior_event_handler (gdb_client_data data)
   inferior_event_handler (INF_REG_EVENT, NULL);
 }
 
-/* Open the process record target.  */
+/* Open the process record target for 'core' files.  */
 
 static void
 record_full_core_open_1 (const char *name, int from_tty)
@@ -930,7 +937,7 @@ record_full_core_open_1 (const char *name, int from_tty)
   record_full_restore ();
 }
 
-/* "open" target method for 'live' processes.  */
+/* Open the process record target for 'live' processes.  */
 
 static void
 record_full_open_1 (const char *name, int from_tty)
@@ -954,10 +961,10 @@ record_full_open_1 (const char *name, int from_tty)
 
 static void record_full_init_record_breakpoints (void);
 
-/* "open" target method.  Open the process record target.  */
+/* Open the process record target.  */
 
-void
-record_full_base_target::open (const char *name, int from_tty)
+static void
+record_full_open (const char *name, int from_tty)
 {
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
@@ -1005,15 +1012,11 @@ record_full_base_target::close ()
     }
 
   /* Release record_full_core_buf_list.  */
-  if (record_full_core_buf_list)
+  while (record_full_core_buf_list)
     {
-      for (entry = record_full_core_buf_list->prev; entry;
-          entry = entry->prev)
-       {
-         xfree (record_full_core_buf_list);
-         record_full_core_buf_list = entry;
-       }
-      record_full_core_buf_list = NULL;
+      entry = record_full_core_buf_list;
+      record_full_core_buf_list = record_full_core_buf_list->prev;
+      xfree (entry);
     }
 
   if (record_full_async_inferior_event_token)
@@ -1030,7 +1033,7 @@ record_full_base_target::async (int enable)
   else
     clear_async_event_handler (record_full_async_inferior_event_token);
 
-  beneath->async (enable);
+  beneath ()->async (enable);
 }
 
 static int record_full_resume_step = 0;
@@ -1093,9 +1096,9 @@ record_full_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
         }
 
       /* Make sure the target beneath reports all signals.  */
-      target_pass_signals (0, NULL);
+      target_pass_signals ({});
 
-      this->beneath->resume (ptid, step, signal);
+      this->beneath ()->resume (ptid, step, signal);
     }
 
   /* We are about to start executing the inferior (or simulate it),
@@ -1110,7 +1113,7 @@ void
 record_full_target::commit_resume ()
 {
   if (!RECORD_FULL_IS_REPLAY)
-    beneath->commit_resume ();
+    beneath ()->commit_resume ();
 }
 
 static int record_full_get_sig = 0;
@@ -1131,18 +1134,6 @@ record_full_sig_handler (int signo)
   record_full_get_sig = 1;
 }
 
-static void
-record_full_wait_cleanups (void *ignore)
-{
-  if (execution_direction == EXEC_REVERSE)
-    {
-      if (record_full_list->next)
-       record_full_list = record_full_list->next;
-    }
-  else
-    record_full_list = record_full_list->prev;
-}
-
 /* "wait" target method for process record target.
 
    In record mode, the target is always run in singlestep mode
@@ -1192,7 +1183,7 @@ record_full_wait_1 (struct target_ops *ops,
       if (record_full_resume_step)
        {
          /* This is a single step.  */
-         return ops->beneath->wait (ptid, status, options);
+         return ops->beneath ()->wait (ptid, status, options);
        }
       else
        {
@@ -1203,9 +1194,7 @@ record_full_wait_1 (struct target_ops *ops,
 
          while (1)
            {
-             struct thread_info *tp;
-
-             ret = ops->beneath->wait (ptid, status, options);
+             ret = ops->beneath ()->wait (ptid, status, options);
              if (status->kind == TARGET_WAITKIND_IGNORE)
                {
                  if (record_debug)
@@ -1215,7 +1204,7 @@ record_full_wait_1 (struct target_ops *ops,
                  return ret;
                }
 
-             ALL_NON_EXITED_THREADS (tp)
+             for (thread_info *tp : all_non_exited_threads ())
                 delete_single_step_breakpoints (tp);
 
              if (record_full_resume_step)
@@ -1281,8 +1270,8 @@ record_full_wait_1 (struct target_ops *ops,
                                            "Process record: record_full_wait "
                                            "issuing one more step in the "
                                            "target beneath\n");
-                     ops->beneath->resume (ptid, step, GDB_SIGNAL_0);
-                     ops->beneath->commit_resume ();
+                     ops->beneath ()->resume (ptid, step, GDB_SIGNAL_0);
+                     ops->beneath ()->commit_resume ();
                      continue;
                    }
                }
@@ -1301,144 +1290,162 @@ record_full_wait_1 (struct target_ops *ops,
       const struct address_space *aspace = regcache->aspace ();
       int continue_flag = 1;
       int first_record_full_end = 1;
-      struct cleanup *old_cleanups
-       = make_cleanup (record_full_wait_cleanups, 0);
-      CORE_ADDR tmp_pc;
 
-      record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
-      status->kind = TARGET_WAITKIND_STOPPED;
-
-      /* Check breakpoint when forward execute.  */
-      if (execution_direction == EXEC_FORWARD)
+      try
        {
-         tmp_pc = regcache_read_pc (regcache);
-         if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
-                                                 &record_full_stop_reason))
-           {
-             if (record_debug)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "Process record: break at %s.\n",
-                                   paddress (gdbarch, tmp_pc));
-             goto replay_out;
-           }
-       }
+         CORE_ADDR tmp_pc;
 
-      /* If GDB is in terminal_inferior mode, it will not get the signal.
-         And in GDB replay mode, GDB doesn't need to be in terminal_inferior
-         mode, because inferior will not executed.
-         Then set it to terminal_ours to make GDB get the signal.  */
-      target_terminal::ours ();
+         record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
+         status->kind = TARGET_WAITKIND_STOPPED;
 
-      /* In EXEC_FORWARD mode, record_full_list points to the tail of prev
-         instruction.  */
-      if (execution_direction == EXEC_FORWARD && record_full_list->next)
-       record_full_list = record_full_list->next;
-
-      /* Loop over the record_full_list, looking for the next place to
-        stop.  */
-      do
-       {
-         /* Check for beginning and end of log.  */
-         if (execution_direction == EXEC_REVERSE
-             && record_full_list == &record_full_first)
+         /* Check breakpoint when forward execute.  */
+         if (execution_direction == EXEC_FORWARD)
            {
-             /* Hit beginning of record log in reverse.  */
-             status->kind = TARGET_WAITKIND_NO_HISTORY;
-             break;
-           }
-         if (execution_direction != EXEC_REVERSE && !record_full_list->next)
-           {
-             /* Hit end of record log going forward.  */
-             status->kind = TARGET_WAITKIND_NO_HISTORY;
-             break;
+             tmp_pc = regcache_read_pc (regcache);
+             if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
+                                                     &record_full_stop_reason))
+               {
+                 if (record_debug)
+                   fprintf_unfiltered (gdb_stdlog,
+                                       "Process record: break at %s.\n",
+                                       paddress (gdbarch, tmp_pc));
+                 goto replay_out;
+               }
            }
 
-          record_full_exec_insn (regcache, gdbarch, record_full_list);
-
-         if (record_full_list->type == record_full_end)
+         /* If GDB is in terminal_inferior mode, it will not get the
+            signal.  And in GDB replay mode, GDB doesn't need to be
+            in terminal_inferior mode, because inferior will not
+            executed.  Then set it to terminal_ours to make GDB get
+            the signal.  */
+         target_terminal::ours ();
+
+         /* In EXEC_FORWARD mode, record_full_list points to the tail of prev
+            instruction.  */
+         if (execution_direction == EXEC_FORWARD && record_full_list->next)
+           record_full_list = record_full_list->next;
+
+         /* Loop over the record_full_list, looking for the next place to
+            stop.  */
+         do
            {
-             if (record_debug > 1)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "Process record: record_full_end %s to "
-                                   "inferior.\n",
-                                   host_address_to_string (record_full_list));
-
-             if (first_record_full_end && execution_direction == EXEC_REVERSE)
+             /* Check for beginning and end of log.  */
+             if (execution_direction == EXEC_REVERSE
+                 && record_full_list == &record_full_first)
                {
-                 /* When reverse excute, the first record_full_end is the
-                    part of current instruction.  */
-                 first_record_full_end = 0;
+                 /* Hit beginning of record log in reverse.  */
+                 status->kind = TARGET_WAITKIND_NO_HISTORY;
+                 break;
                }
-             else
+             if (execution_direction != EXEC_REVERSE
+                 && !record_full_list->next)
                {
-                 /* In EXEC_REVERSE mode, this is the record_full_end of prev
-                    instruction.
-                    In EXEC_FORWARD mode, this is the record_full_end of
-                    current instruction.  */
-                 /* step */
-                 if (record_full_resume_step)
+                 /* Hit end of record log going forward.  */
+                 status->kind = TARGET_WAITKIND_NO_HISTORY;
+                 break;
+               }
+
+             record_full_exec_insn (regcache, gdbarch, record_full_list);
+
+             if (record_full_list->type == record_full_end)
+               {
+                 if (record_debug > 1)
+                   fprintf_unfiltered
+                     (gdb_stdlog,
+                      "Process record: record_full_end %s to "
+                      "inferior.\n",
+                      host_address_to_string (record_full_list));
+
+                 if (first_record_full_end
+                     && execution_direction == EXEC_REVERSE)
                    {
-                     if (record_debug > 1)
-                       fprintf_unfiltered (gdb_stdlog,
-                                           "Process record: step.\n");
-                     continue_flag = 0;
+                     /* When reverse excute, the first
+                        record_full_end is the part of current
+                        instruction.  */
+                     first_record_full_end = 0;
                    }
-
-                 /* check breakpoint */
-                 tmp_pc = regcache_read_pc (regcache);
-                 if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
-                                                         &record_full_stop_reason))
+                 else
                    {
-                     if (record_debug)
-                       fprintf_unfiltered (gdb_stdlog,
-                                           "Process record: break "
-                                           "at %s.\n",
-                                           paddress (gdbarch, tmp_pc));
+                     /* In EXEC_REVERSE mode, this is the
+                        record_full_end of prev instruction.  In
+                        EXEC_FORWARD mode, this is the
+                        record_full_end of current instruction.  */
+                     /* step */
+                     if (record_full_resume_step)
+                       {
+                         if (record_debug > 1)
+                           fprintf_unfiltered (gdb_stdlog,
+                                               "Process record: step.\n");
+                         continue_flag = 0;
+                       }
 
-                     continue_flag = 0;
-                   }
+                     /* check breakpoint */
+                     tmp_pc = regcache_read_pc (regcache);
+                     if (record_check_stopped_by_breakpoint
+                         (aspace, tmp_pc, &record_full_stop_reason))
+                       {
+                         if (record_debug)
+                           fprintf_unfiltered (gdb_stdlog,
+                                               "Process record: break "
+                                               "at %s.\n",
+                                               paddress (gdbarch, tmp_pc));
 
-                 if (record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
-                   {
-                     if (record_debug)
-                       fprintf_unfiltered (gdb_stdlog,
-                                           "Process record: hit hw "
-                                           "watchpoint.\n");
-                     continue_flag = 0;
+                         continue_flag = 0;
+                       }
+
+                     if (record_full_stop_reason
+                         == TARGET_STOPPED_BY_WATCHPOINT)
+                       {
+                         if (record_debug)
+                           fprintf_unfiltered (gdb_stdlog,
+                                               "Process record: hit hw "
+                                               "watchpoint.\n");
+                         continue_flag = 0;
+                       }
+                     /* Check target signal */
+                     if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
+                       /* FIXME: better way to check */
+                       continue_flag = 0;
                    }
-                 /* Check target signal */
-                 if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
-                   /* FIXME: better way to check */
-                   continue_flag = 0;
                }
-           }
 
-         if (continue_flag)
-           {
-             if (execution_direction == EXEC_REVERSE)
+             if (continue_flag)
                {
-                 if (record_full_list->prev)
-                   record_full_list = record_full_list->prev;
-               }
-             else
-               {
-                 if (record_full_list->next)
-                   record_full_list = record_full_list->next;
+                 if (execution_direction == EXEC_REVERSE)
+                   {
+                     if (record_full_list->prev)
+                       record_full_list = record_full_list->prev;
+                   }
+                 else
+                   {
+                     if (record_full_list->next)
+                       record_full_list = record_full_list->next;
+                   }
                }
            }
+         while (continue_flag);
+
+       replay_out:
+         if (record_full_get_sig)
+           status->value.sig = GDB_SIGNAL_INT;
+         else if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
+           /* FIXME: better way to check */
+           status->value.sig = record_full_list->u.end.sigval;
+         else
+           status->value.sig = GDB_SIGNAL_TRAP;
        }
-      while (continue_flag);
-
-replay_out:
-      if (record_full_get_sig)
-       status->value.sig = GDB_SIGNAL_INT;
-      else if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
-       /* FIXME: better way to check */
-       status->value.sig = record_full_list->u.end.sigval;
-      else
-       status->value.sig = GDB_SIGNAL_TRAP;
+      catch (const gdb_exception &ex)
+       {
+         if (execution_direction == EXEC_REVERSE)
+           {
+             if (record_full_list->next)
+               record_full_list = record_full_list->next;
+           }
+         else
+           record_full_list = record_full_list->prev;
 
-      discard_cleanups (old_cleanups);
+         throw;
+       }
     }
 
   signal (SIGINT, handle_sigint);
@@ -1469,7 +1476,7 @@ record_full_base_target::stopped_by_watchpoint ()
   if (RECORD_FULL_IS_REPLAY)
     return record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
   else
-    return beneath->stopped_by_watchpoint ();
+    return beneath ()->stopped_by_watchpoint ();
 }
 
 bool
@@ -1478,7 +1485,7 @@ record_full_base_target::stopped_data_address (CORE_ADDR *addr_p)
   if (RECORD_FULL_IS_REPLAY)
     return false;
   else
-    return this->beneath->stopped_data_address (addr_p);
+    return this->beneath ()->stopped_data_address (addr_p);
 }
 
 /* The stopped_by_sw_breakpoint method of target record-full.  */
@@ -1599,10 +1606,10 @@ record_full_target::store_registers (struct regcache *regcache, int regno)
                  for (i = 0;
                       i < gdbarch_num_regs (regcache->arch ());
                       i++)
-                   regcache_invalidate (regcache, i);
+                   regcache->invalidate (i);
                }
              else
-               regcache_invalidate (regcache, regno);
+               regcache->invalidate (regno);
 
              error (_("Process record canceled the operation."));
            }
@@ -1613,7 +1620,7 @@ record_full_target::store_registers (struct regcache *regcache, int regno)
 
       record_full_registers_change (regcache, regno);
     }
-  this->beneath->store_registers (regcache, regno);
+  this->beneath ()->store_registers (regcache, regno);
 }
 
 /* "xfer_partial" method.  Behavior is conditional on
@@ -1678,8 +1685,8 @@ record_full_target::xfer_partial (enum target_object object,
        record_full_insn_num++;
     }
 
-  return this->beneath->xfer_partial (object, annex, readbuf, writebuf, offset,
-                                     len, xfered_len);
+  return this->beneath ()->xfer_partial (object, annex, readbuf, writebuf,
+                                        offset, len, xfered_len);
 }
 
 /* This structure represents a breakpoint inserted while the record
@@ -1691,6 +1698,15 @@ record_full_target::xfer_partial (enum target_object object,
 
 struct record_full_breakpoint
 {
+  record_full_breakpoint (struct address_space *address_space_,
+                         CORE_ADDR addr_,
+                         bool in_target_beneath_)
+    : address_space (address_space_),
+      addr (addr_),
+      in_target_beneath (in_target_beneath_)
+  {
+  }
+
   /* The address and address space the breakpoint was set at.  */
   struct address_space *address_space;
   CORE_ADDR addr;
@@ -1698,15 +1714,12 @@ struct record_full_breakpoint
   /* True when the breakpoint has been also installed in the target
      beneath.  This will be false for breakpoints set during replay or
      when recording.  */
-  int in_target_beneath;
+  bool in_target_beneath;
 };
 
-typedef struct record_full_breakpoint *record_full_breakpoint_p;
-DEF_VEC_P(record_full_breakpoint_p);
-
 /* The list of breakpoints inserted while the record target is
    active.  */
-VEC(record_full_breakpoint_p) *record_full_breakpoints = NULL;
+static std::vector<record_full_breakpoint> record_full_breakpoints;
 
 static void
 record_full_sync_record_breakpoints (struct bp_location *loc, void *data)
@@ -1716,14 +1729,10 @@ record_full_sync_record_breakpoints (struct bp_location *loc, void *data)
 
   if (loc->inserted)
     {
-      struct record_full_breakpoint *bp = XNEW (struct record_full_breakpoint);
-
-      bp->addr = loc->target_info.placed_address;
-      bp->address_space = loc->target_info.placed_address_space;
-
-      bp->in_target_beneath = 1;
-
-      VEC_safe_push (record_full_breakpoint_p, record_full_breakpoints, bp);
+      record_full_breakpoints.emplace_back
+       (loc->target_info.placed_address_space,
+        loc->target_info.placed_address,
+        1);
     }
 }
 
@@ -1732,7 +1741,7 @@ record_full_sync_record_breakpoints (struct bp_location *loc, void *data)
 static void
 record_full_init_record_breakpoints (void)
 {
-  VEC_free (record_full_breakpoint_p, record_full_breakpoints);
+  record_full_breakpoints.clear ();
 
   iterate_over_bp_locations (record_full_sync_record_breakpoints);
 }
@@ -1745,9 +1754,7 @@ int
 record_full_target::insert_breakpoint (struct gdbarch *gdbarch,
                                       struct bp_target_info *bp_tgt)
 {
-  struct record_full_breakpoint *bp;
-  int in_target_beneath = 0;
-  int ix;
+  bool in_target_beneath = false;
 
   if (!RECORD_FULL_IS_REPLAY)
     {
@@ -1760,34 +1767,29 @@ record_full_target::insert_breakpoint (struct gdbarch *gdbarch,
       scoped_restore restore_operation_disable
        = record_full_gdb_operation_disable_set ();
 
-      int ret = this->beneath->insert_breakpoint (gdbarch, bp_tgt);
+      int ret = this->beneath ()->insert_breakpoint (gdbarch, bp_tgt);
       if (ret != 0)
        return ret;
 
-      in_target_beneath = 1;
+      in_target_beneath = true;
     }
 
   /* Use the existing entries if found in order to avoid duplication
      in record_full_breakpoints.  */
 
-  for (ix = 0;
-       VEC_iterate (record_full_breakpoint_p,
-                   record_full_breakpoints, ix, bp);
-       ++ix)
+  for (const record_full_breakpoint &bp : record_full_breakpoints)
     {
-      if (bp->addr == bp_tgt->placed_address
-         && bp->address_space == bp_tgt->placed_address_space)
+      if (bp.addr == bp_tgt->placed_address
+         && bp.address_space == bp_tgt->placed_address_space)
        {
-         gdb_assert (bp->in_target_beneath == in_target_beneath);
+         gdb_assert (bp.in_target_beneath == in_target_beneath);
          return 0;
        }
     }
 
-  bp = XNEW (struct record_full_breakpoint);
-  bp->addr = bp_tgt->placed_address;
-  bp->address_space = bp_tgt->placed_address_space;
-  bp->in_target_beneath = in_target_beneath;
-  VEC_safe_push (record_full_breakpoint_p, record_full_breakpoints, bp);
+  record_full_breakpoints.emplace_back (bp_tgt->placed_address_space,
+                                       bp_tgt->placed_address,
+                                       in_target_beneath);
   return 0;
 }
 
@@ -1798,33 +1800,28 @@ record_full_target::remove_breakpoint (struct gdbarch *gdbarch,
                                       struct bp_target_info *bp_tgt,
                                       enum remove_bp_reason reason)
 {
-  struct record_full_breakpoint *bp;
-  int ix;
-
-  for (ix = 0;
-       VEC_iterate (record_full_breakpoint_p,
-                   record_full_breakpoints, ix, bp);
-       ++ix)
+  for (auto iter = record_full_breakpoints.begin ();
+       iter != record_full_breakpoints.end ();
+       ++iter)
     {
-      if (bp->addr == bp_tgt->placed_address
-         && bp->address_space == bp_tgt->placed_address_space)
+      struct record_full_breakpoint &bp = *iter;
+
+      if (bp.addr == bp_tgt->placed_address
+         && bp.address_space == bp_tgt->placed_address_space)
        {
-         if (bp->in_target_beneath)
+         if (bp.in_target_beneath)
            {
              scoped_restore restore_operation_disable
                = record_full_gdb_operation_disable_set ();
 
-             int ret = this->beneath->remove_breakpoint (gdbarch, bp_tgt,
-                                                         reason);
+             int ret = this->beneath ()->remove_breakpoint (gdbarch, bp_tgt,
+                                                            reason);
              if (ret != 0)
                return ret;
            }
 
          if (reason == REMOVE_BREAKPOINT)
-           {
-             VEC_unordered_remove (record_full_breakpoint_p,
-                                   record_full_breakpoints, ix);
-           }
+           unordered_remove (record_full_breakpoints, iter);
          return 0;
        }
     }
@@ -2004,7 +2001,8 @@ record_full_goto_entry (struct record_full_entry *p)
 
   registers_changed ();
   reinit_frame_cache ();
-  stop_pc = regcache_read_pc (get_current_regcache ());
+  inferior_thread ()->suspend.stop_pc
+    = regcache_read_pc (get_current_regcache ());
   print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
@@ -2194,10 +2192,10 @@ record_full_core_target::xfer_partial (enum target_object object,
                  else
                    {
                      if (!entry)
-                       return this->beneath->xfer_partial (object, annex,
-                                                           readbuf, writebuf,
-                                                           offset, len,
-                                                           xfered_len);
+                       return this->beneath ()->xfer_partial (object, annex,
+                                                              readbuf, writebuf,
+                                                              offset, len,
+                                                              xfered_len);
 
                      memcpy (readbuf, entry->buf + sec_offset,
                              (size_t) len);
@@ -2214,9 +2212,9 @@ record_full_core_target::xfer_partial (enum target_object object,
        error (_("You can't do that without a process to debug."));
     }
 
-  return this->beneath->xfer_partial (object, annex,
-                                     readbuf, writebuf, offset, len,
-                                     xfered_len);
+  return this->beneath ()->xfer_partial (object, annex,
+                                        readbuf, writebuf, offset, len,
+                                        xfered_len);
 }
 
 /* "insert_breakpoint" method for prec over corefile.  */
@@ -2328,7 +2326,6 @@ static void
 record_full_restore (void)
 {
   uint32_t magic;
-  struct cleanup *old_cleanups;
   struct record_full_entry *rec;
   asection *osec;
   uint32_t osec_size;
@@ -2373,108 +2370,114 @@ record_full_restore (void)
   record_full_arch_list_head = NULL;
   record_full_arch_list_tail = NULL;
   record_full_insn_num = 0;
-  old_cleanups = make_cleanup (record_full_arch_list_cleanups, 0);
-  regcache = get_current_regcache ();
 
-  while (1)
+  try
     {
-      uint8_t rectype;
-      uint32_t regnum, len, signal, count;
-      uint64_t addr;
+      regcache = get_current_regcache ();
 
-      /* We are finished when offset reaches osec_size.  */
-      if (bfd_offset >= osec_size)
-       break;
-      bfdcore_read (core_bfd, osec, &rectype, sizeof (rectype), &bfd_offset);
+      while (1)
+       {
+         uint8_t rectype;
+         uint32_t regnum, len, signal, count;
+         uint64_t addr;
 
-      switch (rectype)
-        {
-        case record_full_reg: /* reg */
-          /* Get register number to regnum.  */
-          bfdcore_read (core_bfd, osec, &regnum,
-                       sizeof (regnum), &bfd_offset);
-         regnum = netorder32 (regnum);
+         /* We are finished when offset reaches osec_size.  */
+         if (bfd_offset >= osec_size)
+           break;
+         bfdcore_read (core_bfd, osec, &rectype, sizeof (rectype), &bfd_offset);
 
-          rec = record_full_reg_alloc (regcache, regnum);
+         switch (rectype)
+           {
+           case record_full_reg: /* reg */
+             /* Get register number to regnum.  */
+             bfdcore_read (core_bfd, osec, &regnum,
+                           sizeof (regnum), &bfd_offset);
+             regnum = netorder32 (regnum);
 
-          /* Get val.  */
-          bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
-                       rec->u.reg.len, &bfd_offset);
+             rec = record_full_reg_alloc (regcache, regnum);
 
-         if (record_debug)
-           fprintf_unfiltered (gdb_stdlog,
-                               "  Reading register %d (1 "
-                               "plus %lu plus %d bytes)\n",
-                               rec->u.reg.num,
-                               (unsigned long) sizeof (regnum),
-                               rec->u.reg.len);
-          break;
-
-        case record_full_mem: /* mem */
-          /* Get len.  */
-          bfdcore_read (core_bfd, osec, &len, 
-                       sizeof (len), &bfd_offset);
-         len = netorder32 (len);
-
-          /* Get addr.  */
-          bfdcore_read (core_bfd, osec, &addr,
-                       sizeof (addr), &bfd_offset);
-         addr = netorder64 (addr);
-
-          rec = record_full_mem_alloc (addr, len);
-
-          /* Get val.  */
-          bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
-                       rec->u.mem.len, &bfd_offset);
+             /* Get val.  */
+             bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
+                           rec->u.reg.len, &bfd_offset);
 
-         if (record_debug)
-           fprintf_unfiltered (gdb_stdlog,
-                               "  Reading memory %s (1 plus "
-                               "%lu plus %lu plus %d bytes)\n",
-                               paddress (get_current_arch (),
-                                         rec->u.mem.addr),
-                               (unsigned long) sizeof (addr),
-                               (unsigned long) sizeof (len),
-                               rec->u.mem.len);
-          break;
-
-        case record_full_end: /* end */
-          rec = record_full_end_alloc ();
-          record_full_insn_num ++;
-
-         /* Get signal value.  */
-         bfdcore_read (core_bfd, osec, &signal, 
-                       sizeof (signal), &bfd_offset);
-         signal = netorder32 (signal);
-         rec->u.end.sigval = (enum gdb_signal) signal;
-
-         /* Get insn count.  */
-         bfdcore_read (core_bfd, osec, &count, 
-                       sizeof (count), &bfd_offset);
-         count = netorder32 (count);
-         rec->u.end.insn_num = count;
-         record_full_insn_count = count + 1;
-         if (record_debug)
-           fprintf_unfiltered (gdb_stdlog,
-                               "  Reading record_full_end (1 + "
-                               "%lu + %lu bytes), offset == %s\n",
-                               (unsigned long) sizeof (signal),
-                               (unsigned long) sizeof (count),
-                               paddress (get_current_arch (),
-                                         bfd_offset));
-          break;
-
-        default:
-          error (_("Bad entry type in core file %s."),
-                bfd_get_filename (core_bfd));
-          break;
-        }
+             if (record_debug)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "  Reading register %d (1 "
+                                   "plus %lu plus %d bytes)\n",
+                                   rec->u.reg.num,
+                                   (unsigned long) sizeof (regnum),
+                                   rec->u.reg.len);
+             break;
 
-      /* Add rec to record arch list.  */
-      record_full_arch_list_add (rec);
-    }
+           case record_full_mem: /* mem */
+             /* Get len.  */
+             bfdcore_read (core_bfd, osec, &len,
+                           sizeof (len), &bfd_offset);
+             len = netorder32 (len);
+
+             /* Get addr.  */
+             bfdcore_read (core_bfd, osec, &addr,
+                           sizeof (addr), &bfd_offset);
+             addr = netorder64 (addr);
+
+             rec = record_full_mem_alloc (addr, len);
+
+             /* Get val.  */
+             bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
+                           rec->u.mem.len, &bfd_offset);
 
-  discard_cleanups (old_cleanups);
+             if (record_debug)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "  Reading memory %s (1 plus "
+                                   "%lu plus %lu plus %d bytes)\n",
+                                   paddress (get_current_arch (),
+                                             rec->u.mem.addr),
+                                   (unsigned long) sizeof (addr),
+                                   (unsigned long) sizeof (len),
+                                   rec->u.mem.len);
+             break;
+
+           case record_full_end: /* end */
+             rec = record_full_end_alloc ();
+             record_full_insn_num ++;
+
+             /* Get signal value.  */
+             bfdcore_read (core_bfd, osec, &signal,
+                           sizeof (signal), &bfd_offset);
+             signal = netorder32 (signal);
+             rec->u.end.sigval = (enum gdb_signal) signal;
+
+             /* Get insn count.  */
+             bfdcore_read (core_bfd, osec, &count,
+                           sizeof (count), &bfd_offset);
+             count = netorder32 (count);
+             rec->u.end.insn_num = count;
+             record_full_insn_count = count + 1;
+             if (record_debug)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "  Reading record_full_end (1 + "
+                                   "%lu + %lu bytes), offset == %s\n",
+                                   (unsigned long) sizeof (signal),
+                                   (unsigned long) sizeof (count),
+                                   paddress (get_current_arch (),
+                                             bfd_offset));
+             break;
+
+           default:
+             error (_("Bad entry type in core file %s."),
+                    bfd_get_filename (core_bfd));
+             break;
+           }
+
+         /* Add rec to record arch list.  */
+         record_full_arch_list_add (rec);
+       }
+    }
+  catch (const gdb_exception &ex)
+    {
+      record_full_list_release (record_full_arch_list_tail);
+      throw;
+    }
 
   /* Add record_full_arch_list_head to the end of record list.  */
   record_full_first.next = record_full_arch_list_head;
@@ -2519,7 +2522,7 @@ static void
 cmd_record_full_restore (const char *args, int from_tty)
 {
   core_file_command (args, from_tty);
-  record_full_ops.open (args, from_tty);
+  record_full_open (args, from_tty);
 }
 
 /* Save the execution log to a file.  We use a modified elf corefile
@@ -2808,9 +2811,9 @@ _initialize_record_full (void)
   record_full_first.next = NULL;
   record_full_first.type = record_full_end;
 
-  add_target (&record_full_ops);
-  add_deprecated_target_alias (&record_full_ops, "record");
-  add_target (&record_full_core_ops);
+  add_target (record_full_target_info, record_full_open);
+  add_deprecated_target_alias (record_full_target_info, "record");
+  add_target (record_full_core_target_info, record_full_open);
 
   add_prefix_cmd ("full", class_obscure, cmd_record_full_start,
                  _("Start full execution recording."), &record_full_cmdlist,
@@ -2829,11 +2832,11 @@ Argument is filename.  File must be created with 'record save'."),
   deprecate_cmd (c, "record full restore");
 
   add_prefix_cmd ("full", class_support, set_record_full_command,
-                 _("Set record options"), &set_record_full_cmdlist,
+                 _("Set record options."), &set_record_full_cmdlist,
                  "set record full ", 0, &set_record_cmdlist);
 
   add_prefix_cmd ("full", class_support, show_record_full_command,
-                 _("Show record options"), &show_record_full_cmdlist,
+                 _("Show record options."), &show_record_full_cmdlist,
                  "show record full ", 0, &show_record_cmdlist);
 
   /* Record instructions number limit command.  */