Multi-target support
[deliverable/binutils-gdb.git] / gdb / record-full.c
index 93c43a1367dc99429f0844ef4cb94ff35ae2d6a5..f759a5185fd2a02a0d7d1235fe9d0ea303c3de9d 100644 (file)
@@ -1,6 +1,6 @@
 /* Process record and replay target for GDB, the GNU debugger.
 
-   Copyright (C) 2013-2017 Free Software Foundation, Inc.
+   Copyright (C) 2013-2020 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"
 #include "event-loop.h"
 #include "inf-loop.h"
 #include "gdb_bfd.h"
-#include "observer.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>
 
 
    Target record has two modes: recording, and replaying.
 
-   In record mode, we intercept the to_resume and to_wait methods.
+   In record mode, we intercept the resume and wait methods.
    Whenever gdb resumes the target, we run the target in single step
    mode, and we build up an execution log in which, for each executed
    instruction, we record all changes in memory and register state.
    This is invisible to the user, to whom it just looks like an
-   ordinary debugging session (except for performance degredation).
+   ordinary debugging session (except for performance degradation).
 
    In replay mode, instead of actually letting the inferior run as a
    process, we simulate its execution by playing back the recorded
@@ -63,7 +64,7 @@
 #define DEFAULT_RECORD_FULL_INSN_MAX_NUM       200000
 
 #define RECORD_FULL_IS_REPLAY \
-     (record_full_list->next || execution_direction == EXEC_REVERSE)
+  (record_full_list->next || ::execution_direction == EXEC_REVERSE)
 
 #define RECORD_FULL_FILE_MAGIC netorder32(0x20091016)
 
@@ -158,7 +159,7 @@ struct record_full_entry
 
 /* If true, query if PREC cannot record memory
    change of next instruction.  */
-int record_full_memory_query = 0;
+bool record_full_memory_query = false;
 
 struct record_full_core_buf_entry
 {
@@ -168,7 +169,7 @@ struct record_full_core_buf_entry
 };
 
 /* Record buf with core target.  */
-static gdb_byte *record_full_core_regbuf = NULL;
+static detached_regcache *record_full_core_regbuf = NULL;
 static struct target_section *record_full_core_start;
 static struct target_section *record_full_core_end;
 static struct record_full_core_buf_entry *record_full_core_buf_list = NULL;
@@ -195,8 +196,8 @@ static struct record_full_entry *record_full_list = &record_full_first;
 static struct record_full_entry *record_full_arch_list_head = NULL;
 static struct record_full_entry *record_full_arch_list_tail = NULL;
 
-/* 1 ask user. 0 auto delete the last struct record_full_entry.  */
-static int record_full_stop_at_limit = 1;
+/* true ask user. false auto delete the last struct record_full_entry.  */
+static bool record_full_stop_at_limit = true;
 /* Maximum allowed number of insns in execution log.  */
 static unsigned int record_full_insn_max_num
        = DEFAULT_RECORD_FULL_INSN_MAX_NUM;
@@ -206,9 +207,153 @@ static unsigned int record_full_insn_num = 0;
    than count of insns presently in execution log).  */
 static ULONGEST record_full_insn_count;
 
-/* The target_ops of process record.  */
-static struct target_ops record_full_ops;
-static struct target_ops record_full_core_ops;
+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:
+  const target_info &info () const override = 0;
+
+  strata stratum () const override { return record_stratum; }
+
+  void close () override;
+  void async (int) override;
+  ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
+  bool stopped_by_watchpoint () override;
+  bool stopped_data_address (CORE_ADDR *) override;
+
+  bool stopped_by_sw_breakpoint () override;
+  bool supports_stopped_by_sw_breakpoint () override;
+
+  bool stopped_by_hw_breakpoint () override;
+  bool supports_stopped_by_hw_breakpoint () override;
+
+  bool can_execute_reverse () override;
+
+  /* Add bookmark target methods.  */
+  gdb_byte *get_bookmark (const char *, int) override;
+  void goto_bookmark (const gdb_byte *, int) override;
+  enum exec_direction_kind execution_direction () override;
+  enum record_method record_method (ptid_t ptid) override;
+  void info_record () override;
+  void save_record (const char *filename) override;
+  bool supports_delete_record () override;
+  void delete_record () override;
+  bool record_is_replaying (ptid_t ptid) override;
+  bool record_will_replay (ptid_t ptid, int dir) override;
+  void record_stop_replaying () override;
+  void goto_record_begin () override;
+  void goto_record_end () override;
+  void goto_record (ULONGEST insn) override;
+};
+
+/* 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 target_info &info () const override
+  { return record_full_target_info; }
+
+  void commit_resume () override;
+  void resume (ptid_t, int, enum gdb_signal) override;
+  void disconnect (const char *, int) override;
+  void detach (inferior *, int) override;
+  void mourn_inferior () override;
+  void kill () override;
+  void store_registers (struct regcache *, int) override;
+  enum target_xfer_status xfer_partial (enum target_object object,
+                                       const char *annex,
+                                       gdb_byte *readbuf,
+                                       const gdb_byte *writebuf,
+                                       ULONGEST offset, ULONGEST len,
+                                       ULONGEST *xfered_len) override;
+  int insert_breakpoint (struct gdbarch *,
+                        struct bp_target_info *) override;
+  int remove_breakpoint (struct gdbarch *,
+                        struct bp_target_info *,
+                        enum remove_bp_reason) override;
+};
+
+/* 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 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;
+  void kill () override;
+  void fetch_registers (struct regcache *regcache, int regno) override;
+  void prepare_to_store (struct regcache *regcache) override;
+  void store_registers (struct regcache *, int) override;
+  enum target_xfer_status xfer_partial (enum target_object object,
+                                       const char *annex,
+                                       gdb_byte *readbuf,
+                                       const gdb_byte *writebuf,
+                                       ULONGEST offset, ULONGEST len,
+                                       ULONGEST *xfered_len) override;
+  int insert_breakpoint (struct gdbarch *,
+                        struct bp_target_info *) override;
+  int remove_breakpoint (struct gdbarch *,
+                        struct bp_target_info *,
+                        enum remove_bp_reason) override;
+
+  bool has_execution (inferior *inf) override;
+};
+
+static record_full_target record_full_ops;
+static record_full_core_target record_full_core_ops;
+
+void
+record_full_target::detach (inferior *inf, int from_tty)
+{
+  record_detach (this, inf, from_tty);
+}
+
+void
+record_full_target::disconnect (const char *args, int from_tty)
+{
+  record_disconnect (this, args, from_tty);
+}
+
+void
+record_full_core_target::disconnect (const char *args, int from_tty)
+{
+  record_disconnect (this, args, from_tty);
+}
+
+void
+record_full_target::mourn_inferior ()
+{
+  record_mourn_inferior (this);
+}
+
+void
+record_full_target::kill ()
+{
+  record_kill (this);
+}
 
 /* See record-full.h.  */
 
@@ -232,8 +377,6 @@ static struct cmd_list_element *record_full_cmdlist;
 
 static void record_full_goto_insn (struct record_full_entry *entry,
                                   enum exec_direction_kind dir);
-static void record_full_save (struct target_ops *self,
-                             const char *recfilename);
 
 /* Alloc and free functions for record_full_reg, record_full_mem, and
    record_full_end entries.  */
@@ -244,7 +387,7 @@ static inline struct record_full_entry *
 record_full_reg_alloc (struct regcache *regcache, int regnum)
 {
   struct record_full_entry *rec;
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = regcache->arch ();
 
   rec = XCNEW (struct record_full_entry);
   rec->type = record_full_reg;
@@ -477,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);
 
@@ -553,78 +696,77 @@ 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
    record the running message of inferior and set them to
    record_full_arch_list, and add it to record_full_list.  */
 
-static int
+static void
 record_full_message (struct regcache *regcache, enum gdb_signal signal)
 {
   int ret;
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  struct cleanup *old_cleanups
-    = make_cleanup (record_full_arch_list_cleanups, 0);
+  struct gdbarch *gdbarch = regcache->arch ();
 
-  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 */
+        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;
+       }
+
+      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;
@@ -633,36 +775,23 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal)
     record_full_list_release_first ();
   else
     record_full_insn_num++;
-
-  return 1;
-}
-
-struct record_full_message_args {
-  struct regcache *regcache;
-  enum gdb_signal signal;
-};
-
-static int
-record_full_message_wrapper (void *args)
-{
-  struct record_full_message_args *record_full_args
-    = (struct record_full_message_args *) args;
-
-  return record_full_message (record_full_args->regcache,
-                             record_full_args->signal);
 }
 
-static int
+static bool
 record_full_message_wrapper_safe (struct regcache *regcache,
                                  enum gdb_signal signal)
 {
-  struct record_full_message_args args;
-
-  args.regcache = regcache;
-  args.signal = signal;
+  try
+    {
+      record_full_message (regcache, signal);
+    }
+  catch (const gdb_exception &ex)
+    {
+      exception_print (gdb_stderr, ex);
+      return false;
+    }
 
-  return catch_errors (record_full_message_wrapper, &args, "",
-                      RETURN_MASK_ALL);
+  return true;
 }
 
 /* Set to 1 if record_full_store_registers and record_full_xfer_partial
@@ -670,16 +799,10 @@ record_full_message_wrapper_safe (struct regcache *regcache,
 
 static int record_full_gdb_operation_disable = 0;
 
-struct cleanup *
+scoped_restore_tmpl<int>
 record_full_gdb_operation_disable_set (void)
 {
-  struct cleanup *old_cleanups = NULL;
-
-  old_cleanups =
-    make_cleanup_restore_integer (&record_full_gdb_operation_disable);
-  record_full_gdb_operation_disable = 1;
-
-  return old_cleanups;
+  return make_scoped_restore (&record_full_gdb_operation_disable, 1);
 }
 
 /* Flag set to TRUE for target_stopped_by_watchpoint.  */
@@ -708,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;
@@ -720,8 +842,7 @@ record_full_exec_insn (struct regcache *regcache,
        /* Nothing to do if the entry is flagged not_accessible.  */
         if (!entry->u.mem.mem_entry_not_accessible)
           {
-            gdb_byte *mem = (gdb_byte *) xmalloc (entry->u.mem.len);
-            struct cleanup *cleanup = make_cleanup (xfree, mem);
+           gdb::byte_vector mem (entry->u.mem.len);
 
             if (record_debug > 1)
               fprintf_unfiltered (gdb_stdlog,
@@ -732,7 +853,8 @@ record_full_exec_insn (struct regcache *regcache,
                                   entry->u.mem.len);
 
             if (record_read_memory (gdbarch,
-                                   entry->u.mem.addr, mem, entry->u.mem.len))
+                                   entry->u.mem.addr, mem.data (),
+                                   entry->u.mem.len))
              entry->u.mem.mem_entry_not_accessible = 1;
             else
               {
@@ -749,7 +871,7 @@ record_full_exec_insn (struct regcache *regcache,
                   }
                 else
                  {
-                   memcpy (record_full_get_loc (entry), mem,
+                   memcpy (record_full_get_loc (entry), mem.data (),
                            entry->u.mem.len);
 
                    /* We've changed memory --- check if a hardware
@@ -761,13 +883,11 @@ record_full_exec_insn (struct regcache *regcache,
                       not doing the change at all if the watchpoint
                       traps.  */
                    if (hardware_watchpoint_inserted_in_range
-                       (get_regcache_aspace (regcache),
+                       (regcache->aspace (),
                         entry->u.mem.addr, entry->u.mem.len))
                      record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
                  }
               }
-
-           do_cleanups (cleanup);
           }
       }
       break;
@@ -787,27 +907,27 @@ 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)
 {
   struct regcache *regcache = get_current_regcache ();
-  int regnum = gdbarch_num_regs (get_regcache_arch (regcache));
+  int regnum = gdbarch_num_regs (regcache->arch ());
   int i;
 
   /* Get record_full_core_regbuf.  */
   target_fetch_registers (regcache, -1);
-  record_full_core_regbuf = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE * regnum);
+  record_full_core_regbuf = new detached_regcache (regcache->arch (), false);
+
   for (i = 0; i < regnum; i ++)
-    regcache_raw_collect (regcache, i,
-                         record_full_core_regbuf + MAX_REGISTER_SIZE * i);
+    record_full_core_regbuf->raw_supply (i, *regcache);
 
   /* Get record_full_core_start and record_full_core_end.  */
   if (build_section_table (core_bfd, &record_full_core_start,
                           &record_full_core_end))
     {
-      xfree (record_full_core_regbuf);
+      delete record_full_core_regbuf;
       record_full_core_regbuf = NULL;
       error (_("\"%s\": Can't find sections: %s"),
             bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
@@ -817,7 +937,7 @@ record_full_core_open_1 (const char *name, int from_tty)
   record_full_restore ();
 }
 
-/* "to_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)
@@ -841,13 +961,11 @@ record_full_open_1 (const char *name, int from_tty)
 
 static void record_full_init_record_breakpoints (void);
 
-/* "to_open" target method.  Open the process record target.  */
+/* Open the process record target.  */
 
 static void
 record_full_open (const char *name, int from_tty)
 {
-  struct target_ops *t;
-
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
 
@@ -871,13 +989,13 @@ record_full_open (const char *name, int from_tty)
 
   record_full_init_record_breakpoints ();
 
-  observer_notify_record_changed (current_inferior (),  1, "full", NULL);
+  gdb::observers::record_changed.notify (current_inferior (),  1, "full", NULL);
 }
 
-/* "to_close" target method.  Close the process record target.  */
+/* "close" target method.  Close the process record target.  */
 
-static void
-record_full_close (struct target_ops *self)
+void
+record_full_base_target::close ()
 {
   struct record_full_core_buf_entry *entry;
 
@@ -889,39 +1007,38 @@ record_full_close (struct target_ops *self)
   /* Release record_full_core_regbuf.  */
   if (record_full_core_regbuf)
     {
-      xfree (record_full_core_regbuf);
+      delete record_full_core_regbuf;
       record_full_core_regbuf = NULL;
     }
 
   /* 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)
     delete_async_event_handler (&record_full_async_inferior_event_token);
 }
 
-/* "to_async" target method.  */
+/* "async" target method.  */
 
-static void
-record_full_async (struct target_ops *ops, int enable)
+void
+record_full_base_target::async (int enable)
 {
   if (enable)
     mark_async_event_handler (record_full_async_inferior_event_token);
   else
     clear_async_event_handler (record_full_async_inferior_event_token);
 
-  ops->beneath->to_async (ops->beneath, enable);
+  beneath ()->async (enable);
 }
 
+/* The PTID and STEP arguments last passed to
+   record_full_target::resume.  */
+static ptid_t record_full_resume_ptid = null_ptid;
 static int record_full_resume_step = 0;
 
 /* True if we've been resumed, and so each record_full_wait call should
@@ -945,15 +1062,15 @@ static int record_full_resumed = 0;
 */
 static enum exec_direction_kind record_full_execution_dir = EXEC_FORWARD;
 
-/* "to_resume" target method.  Resume the process record target.  */
+/* "resume" target method.  Resume the process record target.  */
 
-static void
-record_full_resume (struct target_ops *ops, ptid_t ptid, int step,
-                   enum gdb_signal signal)
+void
+record_full_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
 {
+  record_full_resume_ptid = inferior_ptid;
   record_full_resume_step = step;
   record_full_resumed = 1;
-  record_full_execution_dir = execution_direction;
+  record_full_execution_dir = ::execution_direction;
 
   if (!RECORD_FULL_IS_REPLAY)
     {
@@ -983,9 +1100,9 @@ record_full_resume (struct target_ops *ops, ptid_t ptid, int step,
         }
 
       /* Make sure the target beneath reports all signals.  */
-      target_pass_signals (0, NULL);
+      target_pass_signals ({});
 
-      ops->beneath->to_resume (ops->beneath, ptid, step, signal);
+      this->beneath ()->resume (ptid, step, signal);
     }
 
   /* We are about to start executing the inferior (or simulate it),
@@ -994,18 +1111,18 @@ record_full_resume (struct target_ops *ops, ptid_t ptid, int step,
     target_async (1);
 }
 
-/* "to_commit_resume" method for process record target.  */
+/* "commit_resume" method for process record target.  */
 
-static void
-record_full_commit_resume (struct target_ops *ops)
+void
+record_full_target::commit_resume ()
 {
   if (!RECORD_FULL_IS_REPLAY)
-    ops->beneath->to_commit_resume (ops->beneath);
+    beneath ()->commit_resume ();
 }
 
 static int record_full_get_sig = 0;
 
-/* SIGINT signal handler, registered by "to_wait" method.  */
+/* SIGINT signal handler, registered by "wait" method.  */
 
 static void
 record_full_sig_handler (int signo)
@@ -1021,25 +1138,13 @@ 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;
-}
-
-/* "to_wait" target method for process record target.
+/* "wait" target method for process record target.
 
    In record mode, the target is always run in singlestep mode
-   (even when gdb says to continue).  The to_wait method intercepts
+   (even when gdb says to continue).  The wait method intercepts
    the stop events and determines which ones are to be passed on to
    gdb.  Most stop events are just singlestep events that gdb is not
-   to know about, so the to_wait method just records them and keeps
+   to know about, so the wait method just records them and keeps
    singlestepping.
 
    In replay mode, this function emulates the recorded execution log, 
@@ -1051,7 +1156,8 @@ record_full_wait_1 (struct target_ops *ops,
                    ptid_t ptid, struct target_waitstatus *status,
                    int options)
 {
-  struct cleanup *set_cleanups = record_full_gdb_operation_disable_set ();
+  scoped_restore restore_operation_disable
+    = record_full_gdb_operation_disable_set ();
 
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog,
@@ -1081,20 +1187,19 @@ record_full_wait_1 (struct target_ops *ops,
       if (record_full_resume_step)
        {
          /* This is a single step.  */
-         return ops->beneath->to_wait (ops->beneath, ptid, status, options);
+         return ops->beneath ()->wait (ptid, status, options);
        }
       else
        {
          /* This is not a single step.  */
          ptid_t ret;
          CORE_ADDR tmp_pc;
-         struct gdbarch *gdbarch = target_thread_architecture (inferior_ptid);
+         struct gdbarch *gdbarch
+           = target_thread_architecture (record_full_resume_ptid);
 
          while (1)
            {
-             struct thread_info *tp;
-
-             ret = ops->beneath->to_wait (ops->beneath, ptid, status, options);
+             ret = ops->beneath ()->wait (ptid, status, options);
              if (status->kind == TARGET_WAITKIND_IGNORE)
                {
                  if (record_debug)
@@ -1104,7 +1209,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)
@@ -1115,7 +1220,6 @@ record_full_wait_1 (struct target_ops *ops,
                  && status->value.sig == GDB_SIGNAL_TRAP)
                {
                  struct regcache *regcache;
-                 struct address_space *aspace;
                  enum target_stop_reason *stop_reason_p
                    = &record_full_stop_reason;
 
@@ -1124,9 +1228,11 @@ record_full_wait_1 (struct target_ops *ops,
                     interested in the event.  */
 
                  registers_changed ();
+                 switch_to_thread (current_inferior ()->process_target (),
+                                   ret);
                  regcache = get_current_regcache ();
                  tmp_pc = regcache_read_pc (regcache);
-                 aspace = get_regcache_aspace (regcache);
+                 const struct address_space *aspace = regcache->aspace ();
 
                  if (target_stopped_by_watchpoint ())
                    {
@@ -1156,14 +1262,17 @@ record_full_wait_1 (struct target_ops *ops,
 
                       if (gdbarch_software_single_step_p (gdbarch))
                        {
+                         process_stratum_target *proc_target
+                           = current_inferior ()->process_target ();
+
                          /* Try to insert the software single step breakpoint.
                             If insert success, set step to 0.  */
-                         set_executing (inferior_ptid, 0);
+                         set_executing (proc_target, inferior_ptid, 0);
                          reinit_frame_cache ();
 
                          step = !insert_single_step_breakpoints (gdbarch);
 
-                         set_executing (inferior_ptid, 1);
+                         set_executing (proc_target, inferior_ptid, 1);
                        }
 
                      if (record_debug)
@@ -1171,9 +1280,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->to_resume (ops->beneath, ptid, step,
-                                              GDB_SIGNAL_0);
-                     ops->beneath->to_commit_resume (ops->beneath);
+                     ops->beneath ()->resume (ptid, step, GDB_SIGNAL_0);
+                     ops->beneath ()->commit_resume ();
                      continue;
                    }
                }
@@ -1187,165 +1295,183 @@ record_full_wait_1 (struct target_ops *ops,
     }
   else
     {
+      switch_to_thread (current_inferior ()->process_target (),
+                       record_full_resume_ptid);
       struct regcache *regcache = get_current_regcache ();
-      struct gdbarch *gdbarch = get_regcache_arch (regcache);
-      struct address_space *aspace = get_regcache_aspace (regcache);
+      struct gdbarch *gdbarch = regcache->arch ();
+      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;
-           }
-       }
-
-      /* 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 ();
+         CORE_ADDR tmp_pc;
 
-      /* 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;
+         record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
+         status->kind = TARGET_WAITKIND_STOPPED;
 
-      /* 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)
+               {
+                 /* 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)
                {
-                 /* 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: 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 execute, 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);
 
-  do_cleanups (set_cleanups);
   return inferior_ptid;
 }
 
-static ptid_t
-record_full_wait (struct target_ops *ops,
-                 ptid_t ptid, struct target_waitstatus *status,
-                 int options)
+ptid_t
+record_full_base_target::wait (ptid_t ptid, struct target_waitstatus *status,
+                              int options)
 {
   ptid_t return_ptid;
 
-  return_ptid = record_full_wait_1 (ops, ptid, status, options);
+  return_ptid = record_full_wait_1 (this, ptid, status, options);
   if (status->kind != TARGET_WAITKIND_IGNORE)
     {
       /* We're reporting a stop.  Make sure any spurious
@@ -1356,56 +1482,56 @@ record_full_wait (struct target_ops *ops,
   return return_ptid;
 }
 
-static int
-record_full_stopped_by_watchpoint (struct target_ops *ops)
+bool
+record_full_base_target::stopped_by_watchpoint ()
 {
   if (RECORD_FULL_IS_REPLAY)
     return record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
   else
-    return ops->beneath->to_stopped_by_watchpoint (ops->beneath);
+    return beneath ()->stopped_by_watchpoint ();
 }
 
-static int
-record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+bool
+record_full_base_target::stopped_data_address (CORE_ADDR *addr_p)
 {
   if (RECORD_FULL_IS_REPLAY)
-    return 0;
+    return false;
   else
-    return ops->beneath->to_stopped_data_address (ops->beneath, addr_p);
+    return this->beneath ()->stopped_data_address (addr_p);
 }
 
-/* The to_stopped_by_sw_breakpoint method of target record-full.  */
+/* The stopped_by_sw_breakpoint method of target record-full.  */
 
-static int
-record_full_stopped_by_sw_breakpoint (struct target_ops *ops)
+bool
+record_full_base_target::stopped_by_sw_breakpoint ()
 {
   return record_full_stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
 }
 
-/* The to_supports_stopped_by_sw_breakpoint method of target
+/* The supports_stopped_by_sw_breakpoint method of target
    record-full.  */
 
-static int
-record_full_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
+bool
+record_full_base_target::supports_stopped_by_sw_breakpoint ()
 {
-  return 1;
+  return true;
 }
 
-/* The to_stopped_by_hw_breakpoint method of target record-full.  */
+/* The stopped_by_hw_breakpoint method of target record-full.  */
 
-static int
-record_full_stopped_by_hw_breakpoint (struct target_ops *ops)
+bool
+record_full_base_target::stopped_by_hw_breakpoint ()
 {
   return record_full_stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
 }
 
-/* The to_supports_stopped_by_sw_breakpoint method of target
+/* The supports_stopped_by_sw_breakpoint method of target
    record-full.  */
 
-static int
-record_full_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
+bool
+record_full_base_target::supports_stopped_by_hw_breakpoint ()
 {
-  return 1;
+  return true;
 }
 
 /* Record registers change (by user or by GDB) to list as an instruction.  */
@@ -1423,7 +1549,7 @@ record_full_registers_change (struct regcache *regcache, int regnum)
     {
       int i;
 
-      for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
+      for (i = 0; i < gdbarch_num_regs (regcache->arch ()); i++)
        {
          if (record_full_arch_list_add_reg (regcache, i))
            {
@@ -1455,12 +1581,10 @@ record_full_registers_change (struct regcache *regcache, int regnum)
     record_full_insn_num++;
 }
 
-/* "to_store_registers" method for process record target.  */
+/* "store_registers" method for process record target.  */
 
-static void
-record_full_store_registers (struct target_ops *ops,
-                            struct regcache *regcache,
-                            int regno)
+void
+record_full_target::store_registers (struct regcache *regcache, int regno)
 {
   if (!record_full_gdb_operation_disable)
     {
@@ -1480,7 +1604,7 @@ record_full_store_registers (struct target_ops *ops,
              query (_("Because GDB is in replay mode, changing the value "
                       "of a register will make the execution log unusable "
                       "from this point onward.  Change register %s?"),
-                     gdbarch_register_name (get_regcache_arch (regcache),
+                     gdbarch_register_name (regcache->arch (),
                                               regno));
 
          if (!n)
@@ -1492,12 +1616,12 @@ record_full_store_registers (struct target_ops *ops,
                  int i;
 
                  for (i = 0;
-                      i < gdbarch_num_regs (get_regcache_arch (regcache));
+                      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."));
            }
@@ -1508,19 +1632,19 @@ record_full_store_registers (struct target_ops *ops,
 
       record_full_registers_change (regcache, regno);
     }
-  ops->beneath->to_store_registers (ops->beneath, regcache, regno);
+  this->beneath ()->store_registers (regcache, regno);
 }
 
-/* "to_xfer_partial" method.  Behavior is conditional on
+/* "xfer_partial" method.  Behavior is conditional on
    RECORD_FULL_IS_REPLAY.
    In replay mode, we cannot write memory unles we are willing to
    invalidate the record/replay log from this point forward.  */
 
-static enum target_xfer_status
-record_full_xfer_partial (struct target_ops *ops, enum target_object object,
-                         const char *annex, gdb_byte *readbuf,
-                         const gdb_byte *writebuf, ULONGEST offset,
-                         ULONGEST len, ULONGEST *xfered_len)
+enum target_xfer_status
+record_full_target::xfer_partial (enum target_object object,
+                                 const char *annex, gdb_byte *readbuf,
+                                 const gdb_byte *writebuf, ULONGEST offset,
+                                 ULONGEST len, ULONGEST *xfered_len)
 {
   if (!record_full_gdb_operation_disable
       && (object == TARGET_OBJECT_MEMORY
@@ -1573,9 +1697,8 @@ record_full_xfer_partial (struct target_ops *ops, enum target_object object,
        record_full_insn_num++;
     }
 
-  return ops->beneath->to_xfer_partial (ops->beneath, 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
@@ -1587,6 +1710,15 @@ record_full_xfer_partial (struct target_ops *ops, 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;
@@ -1594,15 +1726,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)
@@ -1612,14 +1741,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);
     }
 }
 
@@ -1628,7 +1753,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);
 }
@@ -1637,14 +1762,11 @@ record_full_init_record_breakpoints (void)
    insert or remove breakpoints in the real target when replaying, nor
    when recording.  */
 
-static int
-record_full_insert_breakpoint (struct target_ops *ops,
-                              struct gdbarch *gdbarch,
-                              struct bp_target_info *bp_tgt)
+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)
     {
@@ -1653,81 +1775,65 @@ record_full_insert_breakpoint (struct target_ops *ops,
         However, we do have to insert software single-step
         breakpoints, in case the target can't hardware step.  To keep
         things simple, we always insert.  */
-      struct cleanup *old_cleanups;
-      int ret;
 
-      old_cleanups = record_full_gdb_operation_disable_set ();
-      ret = ops->beneath->to_insert_breakpoint (ops->beneath, gdbarch, bp_tgt);
-      do_cleanups (old_cleanups);
+      scoped_restore restore_operation_disable
+       = record_full_gdb_operation_disable_set ();
 
+      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;
 }
 
-/* "to_remove_breakpoint" method for process record target.  */
+/* "remove_breakpoint" method for process record target.  */
 
-static int
-record_full_remove_breakpoint (struct target_ops *ops,
-                              struct gdbarch *gdbarch,
-                              struct bp_target_info *bp_tgt,
-                              enum remove_bp_reason reason)
+int
+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)
            {
-             struct cleanup *old_cleanups;
-             int ret;
-
-             old_cleanups = record_full_gdb_operation_disable_set ();
-             ret = ops->beneath->to_remove_breakpoint (ops->beneath, gdbarch,
-                                                       bp_tgt, reason);
-             do_cleanups (old_cleanups);
+             scoped_restore restore_operation_disable
+               = record_full_gdb_operation_disable_set ();
 
+             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;
        }
     }
@@ -1735,19 +1841,18 @@ record_full_remove_breakpoint (struct target_ops *ops,
   gdb_assert_not_reached ("removing unknown breakpoint");
 }
 
-/* "to_can_execute_reverse" method for process record target.  */
+/* "can_execute_reverse" method for process record target.  */
 
-static int
-record_full_can_execute_reverse (struct target_ops *self)
+bool
+record_full_base_target::can_execute_reverse ()
 {
-  return 1;
+  return true;
 }
 
-/* "to_get_bookmark" method for process record and prec over core.  */
+/* "get_bookmark" method for process record and prec over core.  */
 
-static gdb_byte *
-record_full_get_bookmark (struct target_ops *self, const char *args,
-                         int from_tty)
+gdb_byte *
+record_full_base_target::get_bookmark (const char *args, int from_tty)
 {
   char *ret = NULL;
 
@@ -1767,53 +1872,47 @@ record_full_get_bookmark (struct target_ops *self, const char *args,
   return (gdb_byte *) ret;
 }
 
-/* "to_goto_bookmark" method for process record and prec over core.  */
+/* "goto_bookmark" method for process record and prec over core.  */
 
-static void
-record_full_goto_bookmark (struct target_ops *self,
-                          const gdb_byte *raw_bookmark, int from_tty)
+void
+record_full_base_target::goto_bookmark (const gdb_byte *raw_bookmark,
+                                       int from_tty)
 {
   const char *bookmark = (const char *) raw_bookmark;
-  struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
 
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog,
                        "record_full_goto_bookmark receives %s\n", bookmark);
 
+  std::string name_holder;
   if (bookmark[0] == '\'' || bookmark[0] == '\"')
     {
-      char *copy;
-
       if (bookmark[strlen (bookmark) - 1] != bookmark[0])
        error (_("Unbalanced quotes: %s"), bookmark);
 
-
-      copy = savestring (bookmark + 1, strlen (bookmark) - 2);
-      make_cleanup (xfree, copy);
-      bookmark = copy;
+      name_holder = std::string (bookmark + 1, strlen (bookmark) - 2);
+      bookmark = name_holder.c_str ();
     }
 
   record_goto (bookmark);
-
-  do_cleanups (cleanup);
 }
 
-static enum exec_direction_kind
-record_full_execution_direction (struct target_ops *self)
+enum exec_direction_kind
+record_full_base_target::execution_direction ()
 {
   return record_full_execution_dir;
 }
 
-/* The to_record_method method of target record-full.  */
+/* The record_method method of target record-full.  */
 
 enum record_method
-record_full_record_method (struct target_ops *self, ptid_t ptid)
+record_full_base_target::record_method (ptid_t ptid)
 {
   return RECORD_METHOD_FULL;
 }
 
-static void
-record_full_info (struct target_ops *self)
+void
+record_full_base_target::info_record ()
 {
   struct record_full_entry *p;
 
@@ -1856,26 +1955,32 @@ record_full_info (struct target_ops *self)
                   record_full_insn_max_num);
 }
 
-/* The "to_record_delete" target method.  */
+bool
+record_full_base_target::supports_delete_record ()
+{
+  return true;
+}
+
+/* The "delete_record" target method.  */
 
-static void
-record_full_delete (struct target_ops *self)
+void
+record_full_base_target::delete_record ()
 {
   record_full_list_release_following (record_full_list);
 }
 
-/* The "to_record_is_replaying" target method.  */
+/* The "record_is_replaying" target method.  */
 
-static int
-record_full_is_replaying (struct target_ops *self, ptid_t ptid)
+bool
+record_full_base_target::record_is_replaying (ptid_t ptid)
 {
   return RECORD_FULL_IS_REPLAY;
 }
 
-/* The "to_record_will_replay" target method.  */
+/* The "record_will_replay" target method.  */
 
-static int
-record_full_will_replay (struct target_ops *self, ptid_t ptid, int dir)
+bool
+record_full_base_target::record_will_replay (ptid_t ptid, int dir)
 {
   /* We can currently only record when executing forwards.  Should we be able
      to record when executing backwards on targets that support reverse
@@ -1908,14 +2013,15 @@ 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);
 }
 
-/* The "to_goto_record_begin" target method.  */
+/* The "goto_record_begin" target method.  */
 
-static void
-record_full_goto_begin (struct target_ops *self)
+void
+record_full_base_target::goto_record_begin ()
 {
   struct record_full_entry *p = NULL;
 
@@ -1926,10 +2032,10 @@ record_full_goto_begin (struct target_ops *self)
   record_full_goto_entry (p);
 }
 
-/* The "to_goto_record_end" target method.  */
+/* The "goto_record_end" target method.  */
 
-static void
-record_full_goto_end (struct target_ops *self)
+void
+record_full_base_target::goto_record_end ()
 {
   struct record_full_entry *p = NULL;
 
@@ -1942,10 +2048,10 @@ record_full_goto_end (struct target_ops *self)
   record_full_goto_entry (p);
 }
 
-/* The "to_goto_record" target method.  */
+/* The "goto_record" target method.  */
 
-static void
-record_full_goto (struct target_ops *self, ULONGEST target_insn)
+void
+record_full_base_target::goto_record (ULONGEST target_insn)
 {
   struct record_full_entry *p = NULL;
 
@@ -1956,73 +2062,23 @@ record_full_goto (struct target_ops *self, ULONGEST target_insn)
   record_full_goto_entry (p);
 }
 
-/* The "to_record_stop_replaying" target method.  */
+/* The "record_stop_replaying" target method.  */
 
-static void
-record_full_stop_replaying (struct target_ops *self)
+void
+record_full_base_target::record_stop_replaying ()
 {
-  record_full_goto_end (self);
+  goto_record_end ();
 }
 
-static void
-init_record_full_ops (void)
-{
-  record_full_ops.to_shortname = "record-full";
-  record_full_ops.to_longname = "Process record and replay target";
-  record_full_ops.to_doc =
-    "Log program while executing and replay execution from log.";
-  record_full_ops.to_open = record_full_open;
-  record_full_ops.to_close = record_full_close;
-  record_full_ops.to_async = record_full_async;
-  record_full_ops.to_resume = record_full_resume;
-  record_full_ops.to_commit_resume = record_full_commit_resume;
-  record_full_ops.to_wait = record_full_wait;
-  record_full_ops.to_disconnect = record_disconnect;
-  record_full_ops.to_detach = record_detach;
-  record_full_ops.to_mourn_inferior = record_mourn_inferior;
-  record_full_ops.to_kill = record_kill;
-  record_full_ops.to_store_registers = record_full_store_registers;
-  record_full_ops.to_xfer_partial = record_full_xfer_partial;
-  record_full_ops.to_insert_breakpoint = record_full_insert_breakpoint;
-  record_full_ops.to_remove_breakpoint = record_full_remove_breakpoint;
-  record_full_ops.to_stopped_by_watchpoint = record_full_stopped_by_watchpoint;
-  record_full_ops.to_stopped_data_address = record_full_stopped_data_address;
-  record_full_ops.to_stopped_by_sw_breakpoint
-    = record_full_stopped_by_sw_breakpoint;
-  record_full_ops.to_supports_stopped_by_sw_breakpoint
-    = record_full_supports_stopped_by_sw_breakpoint;
-  record_full_ops.to_stopped_by_hw_breakpoint
-    = record_full_stopped_by_hw_breakpoint;
-  record_full_ops.to_supports_stopped_by_hw_breakpoint
-    = record_full_supports_stopped_by_hw_breakpoint;
-  record_full_ops.to_can_execute_reverse = record_full_can_execute_reverse;
-  record_full_ops.to_stratum = record_stratum;
-  /* Add bookmark target methods.  */
-  record_full_ops.to_get_bookmark = record_full_get_bookmark;
-  record_full_ops.to_goto_bookmark = record_full_goto_bookmark;
-  record_full_ops.to_execution_direction = record_full_execution_direction;
-  record_full_ops.to_record_method = record_full_record_method;
-  record_full_ops.to_info_record = record_full_info;
-  record_full_ops.to_save_record = record_full_save;
-  record_full_ops.to_delete_record = record_full_delete;
-  record_full_ops.to_record_is_replaying = record_full_is_replaying;
-  record_full_ops.to_record_will_replay = record_full_will_replay;
-  record_full_ops.to_record_stop_replaying = record_full_stop_replaying;
-  record_full_ops.to_goto_record_begin = record_full_goto_begin;
-  record_full_ops.to_goto_record_end = record_full_goto_end;
-  record_full_ops.to_goto_record = record_full_goto;
-  record_full_ops.to_magic = OPS_MAGIC;
-}
-
-/* "to_resume" method for prec over corefile.  */
+/* "resume" method for prec over corefile.  */
 
-static void
-record_full_core_resume (struct target_ops *ops, ptid_t ptid, int step,
-                        enum gdb_signal signal)
+void
+record_full_core_target::resume (ptid_t ptid, int step,
+                                enum gdb_signal signal)
 {
   record_full_resume_step = step;
   record_full_resumed = 1;
-  record_full_execution_dir = execution_direction;
+  record_full_execution_dir = ::execution_direction;
 
   /* We are about to start executing the inferior (or simulate it),
      let's register it with the event loop.  */
@@ -2030,68 +2086,61 @@ record_full_core_resume (struct target_ops *ops, ptid_t ptid, int step,
     target_async (1);
 }
 
-/* "to_kill" method for prec over corefile.  */
+/* "kill" method for prec over corefile.  */
 
-static void
-record_full_core_kill (struct target_ops *ops)
+void
+record_full_core_target::kill ()
 {
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog, "Process record: record_full_core_kill\n");
 
-  unpush_target (&record_full_core_ops);
+  unpush_target (this);
 }
 
-/* "to_fetch_registers" method for prec over corefile.  */
+/* "fetch_registers" method for prec over corefile.  */
 
-static void
-record_full_core_fetch_registers (struct target_ops *ops,
-                                 struct regcache *regcache,
-                                 int regno)
+void
+record_full_core_target::fetch_registers (struct regcache *regcache,
+                                         int regno)
 {
   if (regno < 0)
     {
-      int num = gdbarch_num_regs (get_regcache_arch (regcache));
+      int num = gdbarch_num_regs (regcache->arch ());
       int i;
 
       for (i = 0; i < num; i ++)
-        regcache_raw_supply (regcache, i,
-                             record_full_core_regbuf + MAX_REGISTER_SIZE * i);
+       regcache->raw_supply (i, *record_full_core_regbuf);
     }
   else
-    regcache_raw_supply (regcache, regno,
-                         record_full_core_regbuf + MAX_REGISTER_SIZE * regno);
+    regcache->raw_supply (regno, *record_full_core_regbuf);
 }
 
-/* "to_prepare_to_store" method for prec over corefile.  */
+/* "prepare_to_store" method for prec over corefile.  */
 
-static void
-record_full_core_prepare_to_store (struct target_ops *self,
-                                  struct regcache *regcache)
+void
+record_full_core_target::prepare_to_store (struct regcache *regcache)
 {
 }
 
-/* "to_store_registers" method for prec over corefile.  */
+/* "store_registers" method for prec over corefile.  */
 
-static void
-record_full_core_store_registers (struct target_ops *ops,
-                             struct regcache *regcache,
-                             int regno)
+void
+record_full_core_target::store_registers (struct regcache *regcache,
+                                         int regno)
 {
   if (record_full_gdb_operation_disable)
-    regcache_raw_collect (regcache, regno,
-                          record_full_core_regbuf + MAX_REGISTER_SIZE * regno);
+    record_full_core_regbuf->raw_supply (regno, *regcache);
   else
     error (_("You can't do that without a process to debug."));
 }
 
-/* "to_xfer_partial" method for prec over corefile.  */
+/* "xfer_partial" method for prec over corefile.  */
 
-static enum target_xfer_status
-record_full_core_xfer_partial (struct target_ops *ops,
-                              enum target_object object,
-                              const char *annex, gdb_byte *readbuf,
-                              const gdb_byte *writebuf, ULONGEST offset,
-                              ULONGEST len, ULONGEST *xfered_len)
+enum target_xfer_status
+record_full_core_target::xfer_partial (enum target_object object,
+                                      const char *annex, gdb_byte *readbuf,
+                                      const gdb_byte *writebuf, ULONGEST offset,
+                                      ULONGEST len, ULONGEST *xfered_len)
 {
   if (object == TARGET_OBJECT_MEMORY)
     {
@@ -2155,11 +2204,10 @@ record_full_core_xfer_partial (struct target_ops *ops,
                  else
                    {
                      if (!entry)
-                       return ops->beneath->to_xfer_partial (ops->beneath,
-                                                             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);
@@ -2176,91 +2224,36 @@ record_full_core_xfer_partial (struct target_ops *ops,
        error (_("You can't do that without a process to debug."));
     }
 
-  return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
-                                       readbuf, writebuf, offset, len,
-                                       xfered_len);
+  return this->beneath ()->xfer_partial (object, annex,
+                                        readbuf, writebuf, offset, len,
+                                        xfered_len);
 }
 
-/* "to_insert_breakpoint" method for prec over corefile.  */
+/* "insert_breakpoint" method for prec over corefile.  */
 
-static int
-record_full_core_insert_breakpoint (struct target_ops *ops,
-                                   struct gdbarch *gdbarch,
-                                   struct bp_target_info *bp_tgt)
+int
+record_full_core_target::insert_breakpoint (struct gdbarch *gdbarch,
+                                           struct bp_target_info *bp_tgt)
 {
   return 0;
 }
 
-/* "to_remove_breakpoint" method for prec over corefile.  */
+/* "remove_breakpoint" method for prec over corefile.  */
 
-static int
-record_full_core_remove_breakpoint (struct target_ops *ops,
-                                   struct gdbarch *gdbarch,
-                                   struct bp_target_info *bp_tgt,
-                                   enum remove_bp_reason reason)
+int
+record_full_core_target::remove_breakpoint (struct gdbarch *gdbarch,
+                                           struct bp_target_info *bp_tgt,
+                                           enum remove_bp_reason reason)
 {
   return 0;
 }
 
-/* "to_has_execution" method for prec over corefile.  */
+/* "has_execution" method for prec over corefile.  */
 
-static int
-record_full_core_has_execution (struct target_ops *ops, ptid_t the_ptid)
+bool
+record_full_core_target::has_execution (inferior *inf)
 {
-  return 1;
-}
-
-static void
-init_record_full_core_ops (void)
-{
-  record_full_core_ops.to_shortname = "record-core";
-  record_full_core_ops.to_longname = "Process record and replay target";
-  record_full_core_ops.to_doc =
-    "Log program while executing and replay execution from log.";
-  record_full_core_ops.to_open = record_full_open;
-  record_full_core_ops.to_close = record_full_close;
-  record_full_core_ops.to_async = record_full_async;
-  record_full_core_ops.to_resume = record_full_core_resume;
-  record_full_core_ops.to_wait = record_full_wait;
-  record_full_core_ops.to_kill = record_full_core_kill;
-  record_full_core_ops.to_fetch_registers = record_full_core_fetch_registers;
-  record_full_core_ops.to_prepare_to_store = record_full_core_prepare_to_store;
-  record_full_core_ops.to_store_registers = record_full_core_store_registers;
-  record_full_core_ops.to_xfer_partial = record_full_core_xfer_partial;
-  record_full_core_ops.to_insert_breakpoint
-    = record_full_core_insert_breakpoint;
-  record_full_core_ops.to_remove_breakpoint
-    = record_full_core_remove_breakpoint;
-  record_full_core_ops.to_stopped_by_watchpoint
-    = record_full_stopped_by_watchpoint;
-  record_full_core_ops.to_stopped_data_address
-    = record_full_stopped_data_address;
-  record_full_core_ops.to_stopped_by_sw_breakpoint
-    = record_full_stopped_by_sw_breakpoint;
-  record_full_core_ops.to_supports_stopped_by_sw_breakpoint
-    = record_full_supports_stopped_by_sw_breakpoint;
-  record_full_core_ops.to_stopped_by_hw_breakpoint
-    = record_full_stopped_by_hw_breakpoint;
-  record_full_core_ops.to_supports_stopped_by_hw_breakpoint
-    = record_full_supports_stopped_by_hw_breakpoint;
-  record_full_core_ops.to_can_execute_reverse
-    = record_full_can_execute_reverse;
-  record_full_core_ops.to_has_execution = record_full_core_has_execution;
-  record_full_core_ops.to_stratum = record_stratum;
-  /* Add bookmark target methods.  */
-  record_full_core_ops.to_get_bookmark = record_full_get_bookmark;
-  record_full_core_ops.to_goto_bookmark = record_full_goto_bookmark;
-  record_full_core_ops.to_execution_direction
-    = record_full_execution_direction;
-  record_full_core_ops.to_record_method = record_full_record_method;
-  record_full_core_ops.to_info_record = record_full_info;
-  record_full_core_ops.to_delete_record = record_full_delete;
-  record_full_core_ops.to_record_is_replaying = record_full_is_replaying;
-  record_full_core_ops.to_record_will_replay = record_full_will_replay;
-  record_full_core_ops.to_goto_record_begin = record_full_goto_begin;
-  record_full_core_ops.to_goto_record_end = record_full_goto_end;
-  record_full_core_ops.to_goto_record = record_full_goto;
-  record_full_core_ops.to_magic = OPS_MAGIC;
+  return true;
 }
 
 /* Record log save-file format
@@ -2345,7 +2338,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;
@@ -2370,9 +2362,9 @@ record_full_restore (void)
                        osec ? "succeeded" : "failed");
   if (osec == NULL)
     return;
-  osec_size = bfd_section_size (core_bfd, osec);
+  osec_size = bfd_section_size (osec);
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "%s", bfd_section_name (core_bfd, osec));
+    fprintf_unfiltered (gdb_stdlog, "%s", bfd_section_name (osec));
 
   /* Check the magic code.  */
   bfdcore_read (core_bfd, osec, &magic, sizeof (magic), &bfd_offset);
@@ -2390,108 +2382,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);
 
-  discard_cleanups (old_cleanups);
+             /* 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);
+
+             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;
@@ -2533,7 +2531,7 @@ bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset)
    corefile format, with an extra section for our data.  */
 
 static void
-cmd_record_full_restore (char *args, int from_tty)
+cmd_record_full_restore (const char *args, int from_tty)
 {
   core_file_command (args, from_tty);
   record_full_open (args, from_tty);
@@ -2542,14 +2540,13 @@ cmd_record_full_restore (char *args, int from_tty)
 /* Save the execution log to a file.  We use a modified elf corefile
    format, with an extra section for our data.  */
 
-static void
-record_full_save (struct target_ops *self, const char *recfilename)
+void
+record_full_base_target::save_record (const char *recfilename)
 {
   struct record_full_entry *cur_record_full_list;
   uint32_t magic;
   struct regcache *regcache;
   struct gdbarch *gdbarch;
-  struct cleanup *set_cleanups;
   int save_size = 0;
   asection *osec = NULL;
   int bfd_offset = 0;
@@ -2570,10 +2567,11 @@ record_full_save (struct target_ops *self, const char *recfilename)
 
   /* Get the values of regcache and gdbarch.  */
   regcache = get_current_regcache ();
-  gdbarch = get_regcache_arch (regcache);
+  gdbarch = regcache->arch ();
 
   /* Disable the GDB operation record.  */
-  set_cleanups = record_full_gdb_operation_disable_set ();
+  scoped_restore restore_operation_disable
+    = record_full_gdb_operation_disable_set ();
 
   /* Reverse execute to the begin of record list.  */
   while (1)
@@ -2613,10 +2611,9 @@ record_full_save (struct target_ops *self, const char *recfilename)
     error (_("Failed to create 'precord' section for corefile %s: %s"),
           recfilename,
            bfd_errmsg (bfd_get_error ()));
-  bfd_set_section_size (obfd.get (), osec, save_size);
-  bfd_set_section_vma (obfd.get (), osec, 0);
-  bfd_set_section_alignment (obfd.get (), osec, 0);
-  bfd_section_lma (obfd.get (), osec) = 0;
+  bfd_set_section_size (osec, save_size);
+  bfd_set_section_vma (osec, 0);
+  bfd_set_section_alignment (osec, 0);
 
   /* Save corefile state.  */
   write_gcore_file (obfd.get ());
@@ -2737,7 +2734,6 @@ record_full_save (struct target_ops *self, const char *recfilename)
         record_full_list = record_full_list->prev;
     }
 
-  do_cleanups (set_cleanups);
   unlink_file.keep ();
 
   /* Succeeded.  */
@@ -2753,9 +2749,10 @@ static void
 record_full_goto_insn (struct record_full_entry *entry,
                       enum exec_direction_kind dir)
 {
-  struct cleanup *set_cleanups = record_full_gdb_operation_disable_set ();
+  scoped_restore restore_operation_disable
+    = record_full_gdb_operation_disable_set ();
   struct regcache *regcache = get_current_regcache ();
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = regcache->arch ();
 
   /* Assume everything is valid: we will hit the entry,
      and we will not hit the end of the recording.  */
@@ -2771,19 +2768,18 @@ record_full_goto_insn (struct record_full_entry *entry,
       else
        record_full_list = record_full_list->next;
     } while (record_full_list != entry);
-  do_cleanups (set_cleanups);
 }
 
 /* Alias for "target record-full".  */
 
 static void
-cmd_record_full_start (char *args, int from_tty)
+cmd_record_full_start (const char *args, int from_tty)
 {
-  execute_command ((char *) "target record-full", from_tty);
+  execute_command ("target record-full", from_tty);
 }
 
 static void
-set_record_full_insn_max_num (char *args, int from_tty,
+set_record_full_insn_max_num (const char *args, int from_tty,
                              struct cmd_list_element *c)
 {
   if (record_full_insn_num > record_full_insn_max_num)
@@ -2800,10 +2796,10 @@ set_record_full_insn_max_num (char *args, int from_tty,
 /* The "set record full" command.  */
 
 static void
-set_record_full_command (char *args, int from_tty)
+set_record_full_command (const char *args, int from_tty)
 {
   printf_unfiltered (_("\"set record full\" must be followed "
-                      "by an apporpriate subcommand.\n"));
+                      "by an appropriate subcommand.\n"));
   help_list (set_record_full_cmdlist, "set record full ", all_commands,
             gdb_stdout);
 }
@@ -2811,7 +2807,7 @@ set_record_full_command (char *args, int from_tty)
 /* The "show record full" command.  */
 
 static void
-show_record_full_command (char *args, int from_tty)
+show_record_full_command (const char *args, int from_tty)
 {
   cmd_show_list (show_record_full_cmdlist, from_tty, "");
 }
@@ -2826,11 +2822,9 @@ _initialize_record_full (void)
   record_full_first.next = NULL;
   record_full_first.type = record_full_end;
 
-  init_record_full_ops ();
-  add_target (&record_full_ops);
-  add_deprecated_target_alias (&record_full_ops, "record");
-  init_record_full_core_ops ();
-  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,
@@ -2849,11 +2843,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.  */
This page took 0.05773 seconds and 4 git commands to generate.