Make print_command_trace varargs
[deliverable/binutils-gdb.git] / gdb / record-full.c
index 14f440093044f3b8b75bbc23d365f710ea2537fb..79f5c0fa0a64079628ef5ff836c489a00b998f1b 100644 (file)
@@ -1,6 +1,6 @@
 /* Process record and replay target for GDB, the GNU debugger.
 
-   Copyright (C) 2013 Free Software Foundation, Inc.
+   Copyright (C) 2013-2018 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -22,7 +22,6 @@
 #include "regcache.h"
 #include "gdbthread.h"
 #include "event-top.h"
-#include "exceptions.h"
 #include "completer.h"
 #include "arch-utils.h"
 #include "gdbcore.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 <signal.h>
 
@@ -45,7 +47,7 @@
 
    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.
@@ -61,7 +63,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)
 
@@ -156,7 +158,7 @@ struct record_full_entry
 
 /* If true, query if PREC cannot record memory
    change of next instruction.  */
-int record_memory_query = 0;
+int record_full_memory_query = 0;
 
 struct record_full_core_buf_entry
 {
@@ -166,7 +168,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;
@@ -199,14 +201,172 @@ static int record_full_stop_at_limit = 1;
 static unsigned int record_full_insn_max_num
        = DEFAULT_RECORD_FULL_INSN_MAX_NUM;
 /* Actual count of insns presently in execution log.  */
-static int record_full_insn_num = 0;
+static unsigned int record_full_insn_num = 0;
 /* Count of insns logged so far (may be larger
    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:
+  record_full_base_target ()
+  { to_stratum = record_stratum; }
+
+  const target_info &info () const override = 0;
+
+  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 (ptid_t) 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.  */
+
+int
+record_full_is_used (void)
+{
+  struct target_ops *t;
+
+  t = find_record_target ();
+  return (t == &record_full_ops
+         || t == &record_full_core_ops);
+}
+
 
 /* Command lists for "set/show record full".  */
 static struct cmd_list_element *set_record_full_cmdlist;
@@ -215,43 +375,8 @@ static struct cmd_list_element *show_record_full_cmdlist;
 /* Command list for "record full".  */
 static struct cmd_list_element *record_full_cmdlist;
 
-/* The beneath function pointers.  */
-static struct target_ops *record_full_beneath_to_resume_ops;
-static void (*record_full_beneath_to_resume) (struct target_ops *, ptid_t, int,
-                                             enum gdb_signal);
-static struct target_ops *record_full_beneath_to_wait_ops;
-static ptid_t (*record_full_beneath_to_wait) (struct target_ops *, ptid_t,
-                                             struct target_waitstatus *,
-                                             int);
-static struct target_ops *record_full_beneath_to_store_registers_ops;
-static void (*record_full_beneath_to_store_registers) (struct target_ops *,
-                                                      struct regcache *,
-                                                      int regno);
-static struct target_ops *record_full_beneath_to_xfer_partial_ops;
-static LONGEST
-  (*record_full_beneath_to_xfer_partial) (struct target_ops *ops,
-                                         enum target_object object,
-                                         const char *annex,
-                                         gdb_byte *readbuf,
-                                         const gdb_byte *writebuf,
-                                         ULONGEST offset,
-                                         LONGEST len);
-static int
-  (*record_full_beneath_to_insert_breakpoint) (struct gdbarch *,
-                                              struct bp_target_info *);
-static int
-  (*record_full_beneath_to_remove_breakpoint) (struct gdbarch *,
-                                              struct bp_target_info *);
-static int (*record_full_beneath_to_stopped_by_watchpoint) (void);
-static int (*record_full_beneath_to_stopped_data_address) (struct target_ops *,
-                                                          CORE_ADDR *);
-static void
-  (*record_full_beneath_to_async) (void (*) (enum inferior_event_type, void *),
-                                  void *);
-
 static void record_full_goto_insn (struct record_full_entry *entry,
                                   enum exec_direction_kind dir);
-static void record_full_save (char *recfilename);
 
 /* Alloc and free functions for record_full_reg, record_full_mem, and
    record_full_end entries.  */
@@ -262,9 +387,9 @@ 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 = xcalloc (1, sizeof (struct record_full_entry));
+  rec = XCNEW (struct record_full_entry);
   rec->type = record_full_reg;
   rec->u.reg.num = regnum;
   rec->u.reg.len = register_size (gdbarch, regnum);
@@ -292,7 +417,7 @@ record_full_mem_alloc (CORE_ADDR addr, int len)
 {
   struct record_full_entry *rec;
 
-  rec = xcalloc (1, sizeof (struct record_full_entry));
+  rec = XCNEW (struct record_full_entry);
   rec->type = record_full_mem;
   rec->u.mem.addr = addr;
   rec->u.mem.len = len;
@@ -320,7 +445,7 @@ record_full_end_alloc (void)
 {
   struct record_full_entry *rec;
 
-  rec = xcalloc (1, sizeof (struct record_full_entry));
+  rec = XCNEW (struct record_full_entry);
   rec->type = record_full_end;
 
   return rec;
@@ -483,7 +608,7 @@ record_full_get_loc (struct record_full_entry *rec)
 /* Record the value of a register NUM to record_full_arch_list.  */
 
 int
-record_arch_list_add_reg (struct regcache *regcache, int regnum)
+record_full_arch_list_add_reg (struct regcache *regcache, int regnum)
 {
   struct record_full_entry *rec;
 
@@ -506,7 +631,7 @@ record_arch_list_add_reg (struct regcache *regcache, int regnum)
    length is LEN to record_full_arch_list.  */
 
 int
-record_arch_list_add_mem (CORE_ADDR addr, int len)
+record_full_arch_list_add_mem (CORE_ADDR addr, int len)
 {
   struct record_full_entry *rec;
 
@@ -537,7 +662,7 @@ record_arch_list_add_mem (CORE_ADDR addr, int len)
    record_full_arch_list.  */
 
 int
-record_arch_list_add_end (void)
+record_full_arch_list_add_end (void)
 {
   struct record_full_entry *rec;
 
@@ -555,30 +680,18 @@ record_arch_list_add_end (void)
 }
 
 static void
-record_full_check_insn_num (int set_terminal)
+record_full_check_insn_num (void)
 {
-  if (record_full_insn_max_num)
+  if (record_full_insn_num == record_full_insn_max_num)
     {
-      gdb_assert (record_full_insn_num <= record_full_insn_max_num);
-      if (record_full_insn_num == record_full_insn_max_num)
+      /* Ask user what to do.  */
+      if (record_full_stop_at_limit)
        {
-         /* Ask user what to do.  */
-         if (record_full_stop_at_limit)
-           {
-             int q;
-
-             if (set_terminal)
-               target_terminal_ours ();
-             q = yquery (_("Do you want to auto delete previous execution "
-                           "log entries when record/replay buffer becomes "
-                           "full (record full stop-at-limit)?"));
-             if (set_terminal)
-               target_terminal_inferior ();
-             if (q)
-               record_full_stop_at_limit = 0;
-             else
-               error (_("Process record: stopped by user."));
-           }
+         if (!yquery (_("Do you want to auto delete previous execution "
+                       "log entries when record/replay buffer becomes "
+                       "full (record full stop-at-limit)?")))
+           error (_("Process record: stopped by user."));
+         record_full_stop_at_limit = 0;
        }
     }
 }
@@ -595,11 +708,11 @@ record_full_arch_list_cleanups (void *ignore)
    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 gdbarch *gdbarch = regcache->arch ();
   struct cleanup *old_cleanups
     = make_cleanup (record_full_arch_list_cleanups, 0);
 
@@ -607,7 +720,7 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal)
   record_full_arch_list_tail = NULL;
 
   /* Check record_full_insn_num.  */
-  record_full_check_insn_num (1);
+  record_full_check_insn_num ();
 
   /* If gdb sends a signal value to target_resume,
      save it in the 'end' field of the previous instruction.
@@ -659,40 +772,28 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal)
   record_full_arch_list_head->prev = record_full_list;
   record_full_list = record_full_arch_list_tail;
 
-  if (record_full_insn_num == record_full_insn_max_num
-      && record_full_insn_max_num)
+  if (record_full_insn_num == record_full_insn_max_num)
     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 = 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 (ex, RETURN_MASK_ALL)
+    {
+      exception_print (gdb_stderr, ex);
+      return false;
+    }
+  END_CATCH
 
-  return catch_errors (record_full_message_wrapper, &args, NULL,
-                      RETURN_MASK_ALL);
+  return true;
 }
 
 /* Set to 1 if record_full_store_registers and record_full_xfer_partial
@@ -700,20 +801,15 @@ record_full_message_wrapper_safe (struct regcache *regcache,
 
 static int record_full_gdb_operation_disable = 0;
 
-struct cleanup *
-record_gdb_operation_disable_set (void)
+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.  */
-static int record_full_hw_watchpoint = 0;
+static enum target_stop_reason record_full_stop_reason
+  = TARGET_STOPPED_BY_NO_REASON;
 
 /* Execute one instruction from the record log.  Each instruction in
    the log will be represented by an arbitrary sequence of register
@@ -728,7 +824,7 @@ record_full_exec_insn (struct regcache *regcache,
     {
     case record_full_reg: /* reg */
       {
-        gdb_byte reg[MAX_REGISTER_SIZE];
+       gdb::byte_vector reg (entry->u.reg.len);
 
         if (record_debug > 1)
           fprintf_unfiltered (gdb_stdlog,
@@ -737,10 +833,10 @@ 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);
+        regcache_cooked_read (regcache, entry->u.reg.num, reg.data ());
         regcache_cooked_write (regcache, entry->u.reg.num, 
                               record_full_get_loc (entry));
-        memcpy (record_full_get_loc (entry), reg, entry->u.reg.len);
+        memcpy (record_full_get_loc (entry), reg.data (), entry->u.reg.len);
       }
       break;
 
@@ -749,7 +845,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 = alloca (entry->u.mem.len);
+           gdb::byte_vector mem (entry->u.mem.len);
 
             if (record_debug > 1)
               fprintf_unfiltered (gdb_stdlog,
@@ -760,7 +856,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
               {
@@ -777,7 +874,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
@@ -789,9 +886,9 @@ 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_hw_watchpoint = 1;
+                     record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
                  }
               }
           }
@@ -800,34 +897,6 @@ record_full_exec_insn (struct regcache *regcache,
     }
 }
 
-static struct target_ops *tmp_to_resume_ops;
-static void (*tmp_to_resume) (struct target_ops *, ptid_t, int,
-                             enum gdb_signal);
-static struct target_ops *tmp_to_wait_ops;
-static ptid_t (*tmp_to_wait) (struct target_ops *, ptid_t,
-                             struct target_waitstatus *,
-                             int);
-static struct target_ops *tmp_to_store_registers_ops;
-static void (*tmp_to_store_registers) (struct target_ops *,
-                                      struct regcache *,
-                                      int regno);
-static struct target_ops *tmp_to_xfer_partial_ops;
-static LONGEST (*tmp_to_xfer_partial) (struct target_ops *ops,
-                                      enum target_object object,
-                                      const char *annex,
-                                      gdb_byte *readbuf,
-                                      const gdb_byte *writebuf,
-                                      ULONGEST offset,
-                                      LONGEST len);
-static int (*tmp_to_insert_breakpoint) (struct gdbarch *,
-                                       struct bp_target_info *);
-static int (*tmp_to_remove_breakpoint) (struct gdbarch *,
-                                       struct bp_target_info *);
-static int (*tmp_to_stopped_by_watchpoint) (void);
-static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
-static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
-static void (*tmp_to_async) (void (*) (enum inferior_event_type, void *), void *);
-
 static void record_full_restore (void);
 
 /* Asynchronous signal handle registered as event loop source for when
@@ -841,27 +910,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 (char *name, int from_tty)
+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 = 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 ()));
@@ -871,13 +940,13 @@ record_full_core_open_1 (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 (char *name, int from_tty)
+record_full_open_1 (const char *name, int from_tty)
 {
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
+    fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open_1\n");
 
   /* check exec */
   if (!target_has_execution)
@@ -890,97 +959,20 @@ record_full_open_1 (char *name, int from_tty)
     error (_("Process record: the current architecture doesn't support "
             "record function."));
 
-  if (!tmp_to_resume)
-    error (_("Could not find 'to_resume' method on the target stack."));
-  if (!tmp_to_wait)
-    error (_("Could not find 'to_wait' method on the target stack."));
-  if (!tmp_to_store_registers)
-    error (_("Could not find 'to_store_registers' "
-            "method on the target stack."));
-  if (!tmp_to_insert_breakpoint)
-    error (_("Could not find 'to_insert_breakpoint' "
-            "method on the target stack."));
-  if (!tmp_to_remove_breakpoint)
-    error (_("Could not find 'to_remove_breakpoint' "
-            "method on the target stack."));
-  if (!tmp_to_stopped_by_watchpoint)
-    error (_("Could not find 'to_stopped_by_watchpoint' "
-            "method on the target stack."));
-  if (!tmp_to_stopped_data_address)
-    error (_("Could not find 'to_stopped_data_address' "
-            "method on the target stack."));
-
   push_target (&record_full_ops);
 }
 
 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 (char *name, int from_tty)
+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");
 
-  /* Check if record target is already running.  */
-  if (current_target.to_stratum == record_stratum)
-    error (_("Process record target already running.  Use \"record stop\" to "
-             "stop record target first."));
-
-  /* Reset the tmp beneath pointers.  */
-  tmp_to_resume_ops = NULL;
-  tmp_to_resume = NULL;
-  tmp_to_wait_ops = NULL;
-  tmp_to_wait = NULL;
-  tmp_to_store_registers_ops = NULL;
-  tmp_to_store_registers = NULL;
-  tmp_to_xfer_partial_ops = NULL;
-  tmp_to_xfer_partial = NULL;
-  tmp_to_insert_breakpoint = NULL;
-  tmp_to_remove_breakpoint = NULL;
-  tmp_to_stopped_by_watchpoint = NULL;
-  tmp_to_stopped_data_address = NULL;
-  tmp_to_async = NULL;
-
-  /* Set the beneath function pointers.  */
-  for (t = current_target.beneath; t != NULL; t = t->beneath)
-    {
-      if (!tmp_to_resume)
-        {
-         tmp_to_resume = t->to_resume;
-         tmp_to_resume_ops = t;
-        }
-      if (!tmp_to_wait)
-        {
-         tmp_to_wait = t->to_wait;
-         tmp_to_wait_ops = t;
-        }
-      if (!tmp_to_store_registers)
-        {
-         tmp_to_store_registers = t->to_store_registers;
-         tmp_to_store_registers_ops = t;
-        }
-      if (!tmp_to_xfer_partial)
-        {
-         tmp_to_xfer_partial = t->to_xfer_partial;
-         tmp_to_xfer_partial_ops = t;
-        }
-      if (!tmp_to_insert_breakpoint)
-       tmp_to_insert_breakpoint = t->to_insert_breakpoint;
-      if (!tmp_to_remove_breakpoint)
-       tmp_to_remove_breakpoint = t->to_remove_breakpoint;
-      if (!tmp_to_stopped_by_watchpoint)
-       tmp_to_stopped_by_watchpoint = t->to_stopped_by_watchpoint;
-      if (!tmp_to_stopped_data_address)
-       tmp_to_stopped_data_address = t->to_stopped_data_address;
-      if (!tmp_to_async)
-       tmp_to_async = t->to_async;
-    }
-  if (!tmp_to_xfer_partial)
-    error (_("Could not find 'to_xfer_partial' method on the target stack."));
+  record_preopen ();
 
   /* Reset */
   record_full_insn_num = 0;
@@ -988,21 +980,6 @@ record_full_open (char *name, int from_tty)
   record_full_list = &record_full_first;
   record_full_list->next = NULL;
 
-  /* Set the tmp beneath pointers to beneath pointers.  */
-  record_full_beneath_to_resume_ops = tmp_to_resume_ops;
-  record_full_beneath_to_resume = tmp_to_resume;
-  record_full_beneath_to_wait_ops = tmp_to_wait_ops;
-  record_full_beneath_to_wait = tmp_to_wait;
-  record_full_beneath_to_store_registers_ops = tmp_to_store_registers_ops;
-  record_full_beneath_to_store_registers = tmp_to_store_registers;
-  record_full_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops;
-  record_full_beneath_to_xfer_partial = tmp_to_xfer_partial;
-  record_full_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
-  record_full_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
-  record_full_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint;
-  record_full_beneath_to_stopped_data_address = tmp_to_stopped_data_address;
-  record_full_beneath_to_async = tmp_to_async;
-
   if (core_bfd)
     record_full_core_open_1 (name, from_tty);
   else
@@ -1015,13 +992,13 @@ record_full_open (char *name, int from_tty)
 
   record_full_init_record_breakpoints ();
 
-  observer_notify_record_changed (current_inferior (),  1);
+  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 (int quitting)
+void
+record_full_base_target::close ()
 {
   struct record_full_core_buf_entry *entry;
 
@@ -1033,7 +1010,7 @@ record_full_close (int quitting)
   /* 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;
     }
 
@@ -1053,6 +1030,19 @@ record_full_close (int quitting)
     delete_async_event_handler (&record_full_async_inferior_event_token);
 }
 
+/* "async" target method.  */
+
+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);
+
+  beneath->async (enable);
+}
+
 static int record_full_resume_step = 0;
 
 /* True if we've been resumed, and so each record_full_wait call should
@@ -1076,15 +1066,14 @@ 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_step = step;
   record_full_resumed = 1;
-  record_full_execution_dir = execution_direction;
+  record_full_execution_dir = ::execution_direction;
 
   if (!RECORD_FULL_IS_REPLAY)
     {
@@ -1102,48 +1091,41 @@ record_full_resume (struct target_ops *ops, ptid_t ptid, int step,
             }
           else
             {
-              /* This arch support soft sigle step.  */
-              if (single_step_breakpoints_inserted ())
+              /* This arch supports soft single step.  */
+              if (thread_has_single_step_breakpoints_set (inferior_thread ()))
                 {
                   /* This is a soft single step.  */
                   record_full_resume_step = 1;
                 }
               else
-                {
-                  /* This is a continue.
-                     Try to insert a soft single step breakpoint.  */
-                  if (!gdbarch_software_single_step (gdbarch,
-                                                     get_current_frame ()))
-                    {
-                      /* This system don't want use soft single step.
-                         Use hard sigle step.  */
-                      step = 1;
-                    }
-                }
+               step = !insert_single_step_breakpoints (gdbarch);
             }
         }
 
       /* Make sure the target beneath reports all signals.  */
       target_pass_signals (0, NULL);
 
-      record_full_beneath_to_resume (record_full_beneath_to_resume_ops,
-                                    ptid, step, signal);
+      this->beneath->resume (ptid, step, signal);
     }
 
   /* We are about to start executing the inferior (or simulate it),
      let's register it with the event loop.  */
   if (target_can_async_p ())
-    {
-      target_async (inferior_event_handler, 0);
-      /* Notify the event loop there's an event to wait for.  We do
-        most of the work in record_full_wait.  */
-      mark_async_event_handler (record_full_async_inferior_event_token);
-    }
+    target_async (1);
+}
+
+/* "commit_resume" method for process record target.  */
+
+void
+record_full_target::commit_resume ()
+{
+  if (!RECORD_FULL_IS_REPLAY)
+    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)
@@ -1171,13 +1153,13 @@ record_full_wait_cleanups (void *ignore)
     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, 
@@ -1189,7 +1171,8 @@ record_full_wait_1 (struct target_ops *ops,
                    ptid_t ptid, struct target_waitstatus *status,
                    int options)
 {
-  struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
+  scoped_restore restore_operation_disable
+    = record_full_gdb_operation_disable_set ();
 
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog,
@@ -1212,13 +1195,14 @@ record_full_wait_1 (struct target_ops *ops,
   record_full_get_sig = 0;
   signal (SIGINT, record_full_sig_handler);
 
+  record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
+
   if (!RECORD_FULL_IS_REPLAY && ops != &record_full_core_ops)
     {
       if (record_full_resume_step)
        {
          /* This is a single step.  */
-         return record_full_beneath_to_wait (record_full_beneath_to_wait_ops,
-                                             ptid, status, options);
+         return ops->beneath->wait (ptid, status, options);
        }
       else
        {
@@ -1229,8 +1213,9 @@ record_full_wait_1 (struct target_ops *ops,
 
          while (1)
            {
-             ret = record_full_beneath_to_wait
-               (record_full_beneath_to_wait_ops, ptid, status, options);
+             struct thread_info *tp;
+
+             ret = ops->beneath->wait (ptid, status, options);
              if (status->kind == TARGET_WAITKIND_IGNORE)
                {
                  if (record_debug)
@@ -1240,8 +1225,8 @@ record_full_wait_1 (struct target_ops *ops,
                  return ret;
                }
 
-              if (single_step_breakpoints_inserted ())
-                remove_single_step_breakpoints ();
+             ALL_NON_EXITED_THREADS (tp)
+                delete_single_step_breakpoints (tp);
 
              if (record_full_resume_step)
                return ret;
@@ -1251,7 +1236,8 @@ 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;
 
                  /* Yes -- this is likely our single-step finishing,
                     but check if there's any reason the core would be
@@ -1260,26 +1246,17 @@ record_full_wait_1 (struct target_ops *ops,
                  registers_changed ();
                  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 ())
                    {
                      /* Always interested in watchpoints.  */
                    }
-                 else if (breakpoint_inserted_here_p (aspace, tmp_pc))
+                 else if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
+                                                              stop_reason_p))
                    {
                      /* There is a breakpoint here.  Let the core
                         handle it.  */
-                     if (software_breakpoint_inserted_here_p (aspace, tmp_pc))
-                       {
-                         struct gdbarch *gdbarch
-                           = get_regcache_arch (regcache);
-                         CORE_ADDR decr_pc_after_break
-                           = gdbarch_decr_pc_after_break (gdbarch);
-                         if (decr_pc_after_break)
-                           regcache_write_pc (regcache,
-                                              tmp_pc + decr_pc_after_break);
-                       }
                    }
                  else
                    {
@@ -1303,9 +1280,9 @@ record_full_wait_1 (struct target_ops *ops,
                             If insert success, set step to 0.  */
                          set_executing (inferior_ptid, 0);
                          reinit_frame_cache ();
-                         if (gdbarch_software_single_step (gdbarch,
-                                                            get_current_frame ()))
-                           step = 0;
+
+                         step = !insert_single_step_breakpoints (gdbarch);
+
                          set_executing (inferior_ptid, 1);
                        }
 
@@ -1314,9 +1291,8 @@ record_full_wait_1 (struct target_ops *ops,
                                            "Process record: record_full_wait "
                                            "issuing one more step in the "
                                            "target beneath\n");
-                     record_full_beneath_to_resume
-                       (record_full_beneath_to_resume_ops, ptid, step,
-                        GDB_SIGNAL_0);
+                     ops->beneath->resume (ptid, step, GDB_SIGNAL_0);
+                     ops->beneath->commit_resume ();
                      continue;
                    }
                }
@@ -1331,35 +1307,28 @@ record_full_wait_1 (struct target_ops *ops,
   else
     {
       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_hw_watchpoint = 0;
+      record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
       status->kind = TARGET_WAITKIND_STOPPED;
 
       /* Check breakpoint when forward execute.  */
       if (execution_direction == EXEC_FORWARD)
        {
          tmp_pc = regcache_read_pc (regcache);
-         if (breakpoint_inserted_here_p (aspace, tmp_pc))
+         if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
+                                                 &record_full_stop_reason))
            {
-             int decr_pc_after_break = gdbarch_decr_pc_after_break (gdbarch);
-
              if (record_debug)
                fprintf_unfiltered (gdb_stdlog,
                                    "Process record: break at %s.\n",
                                    paddress (gdbarch, tmp_pc));
-
-             if (decr_pc_after_break
-                 && !record_full_resume_step
-                 && software_breakpoint_inserted_here_p (aspace, tmp_pc))
-               regcache_write_pc (regcache,
-                                  tmp_pc + decr_pc_after_break);
              goto replay_out;
            }
        }
@@ -1368,7 +1337,7 @@ record_full_wait_1 (struct target_ops *ops,
          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 ();
+      target_terminal::ours ();
 
       /* In EXEC_FORWARD mode, record_full_list points to the tail of prev
          instruction.  */
@@ -1427,27 +1396,19 @@ record_full_wait_1 (struct target_ops *ops,
 
                  /* check breakpoint */
                  tmp_pc = regcache_read_pc (regcache);
-                 if (breakpoint_inserted_here_p (aspace, tmp_pc))
+                 if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
+                                                         &record_full_stop_reason))
                    {
-                     int decr_pc_after_break
-                       = gdbarch_decr_pc_after_break (gdbarch);
-
                      if (record_debug)
                        fprintf_unfiltered (gdb_stdlog,
                                            "Process record: break "
                                            "at %s.\n",
                                            paddress (gdbarch, tmp_pc));
-                     if (decr_pc_after_break
-                         && execution_direction == EXEC_FORWARD
-                         && !record_full_resume_step
-                         && software_breakpoint_inserted_here_p (aspace,
-                                                                 tmp_pc))
-                       regcache_write_pc (regcache,
-                                          tmp_pc + decr_pc_after_break);
+
                      continue_flag = 0;
                    }
 
-                 if (record_full_hw_watchpoint)
+                 if (record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
                    {
                      if (record_debug)
                        fprintf_unfiltered (gdb_stdlog,
@@ -1492,18 +1453,16 @@ replay_out:
 
   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
@@ -1514,72 +1473,56 @@ record_full_wait (struct target_ops *ops,
   return return_ptid;
 }
 
-static int
-record_full_stopped_by_watchpoint (void)
+bool
+record_full_base_target::stopped_by_watchpoint ()
 {
   if (RECORD_FULL_IS_REPLAY)
-    return record_full_hw_watchpoint;
+    return record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
   else
-    return record_full_beneath_to_stopped_by_watchpoint ();
+    return beneath->stopped_by_watchpoint ();
 }
 
-/* "to_disconnect" method for process record target.  */
-
-static void
-record_full_disconnect (struct target_ops *target, char *args, int from_tty)
+bool
+record_full_base_target::stopped_data_address (CORE_ADDR *addr_p)
 {
-  if (record_debug)
-    fprintf_unfiltered (gdb_stdlog,
-                       "Process record: record_full_disconnect\n");
-
-  unpush_target (&record_full_ops);
-  target_disconnect (args, from_tty);
+  if (RECORD_FULL_IS_REPLAY)
+    return false;
+  else
+    return this->beneath->stopped_data_address (addr_p);
 }
 
-/* "to_detach" method for process record target.  */
+/* The stopped_by_sw_breakpoint method of target record-full.  */
 
-static void
-record_full_detach (struct target_ops *ops, char *args, int from_tty)
+bool
+record_full_base_target::stopped_by_sw_breakpoint ()
 {
-  if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: record_full_detach\n");
-
-  unpush_target (&record_full_ops);
-  target_detach (args, from_tty);
+  return record_full_stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
 }
 
-/* "to_mourn_inferior" method for process record target.  */
+/* The supports_stopped_by_sw_breakpoint method of target
+   record-full.  */
 
-static void
-record_full_mourn_inferior (struct target_ops *ops)
+bool
+record_full_base_target::supports_stopped_by_sw_breakpoint ()
 {
-  if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: "
-                                   "record_full_mourn_inferior\n");
-
-  unpush_target (&record_full_ops);
-  target_mourn_inferior ();
+  return true;
 }
 
-/* Close process record target before killing the inferior process.  */
+/* The stopped_by_hw_breakpoint method of target record-full.  */
 
-static void
-record_full_kill (struct target_ops *ops)
+bool
+record_full_base_target::stopped_by_hw_breakpoint ()
 {
-  if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: record_full_kill\n");
-
-  unpush_target (&record_full_ops);
-  target_kill ();
+  return record_full_stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
 }
 
-static int
-record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+/* The supports_stopped_by_sw_breakpoint method of target
+   record-full.  */
+
+bool
+record_full_base_target::supports_stopped_by_hw_breakpoint ()
 {
-  if (RECORD_FULL_IS_REPLAY)
-    return 0;
-  else
-    return record_full_beneath_to_stopped_data_address (ops, addr_p);
+  return true;
 }
 
 /* Record registers change (by user or by GDB) to list as an instruction.  */
@@ -1588,7 +1531,7 @@ static void
 record_full_registers_change (struct regcache *regcache, int regnum)
 {
   /* Check record_full_insn_num.  */
-  record_full_check_insn_num (0);
+  record_full_check_insn_num ();
 
   record_full_arch_list_head = NULL;
   record_full_arch_list_tail = NULL;
@@ -1597,9 +1540,9 @@ 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_arch_list_add_reg (regcache, i))
+         if (record_full_arch_list_add_reg (regcache, i))
            {
              record_full_list_release (record_full_arch_list_tail);
              error (_("Process record: failed to record execution log."));
@@ -1608,13 +1551,13 @@ record_full_registers_change (struct regcache *regcache, int regnum)
     }
   else
     {
-      if (record_arch_list_add_reg (regcache, regnum))
+      if (record_full_arch_list_add_reg (regcache, regnum))
        {
          record_full_list_release (record_full_arch_list_tail);
          error (_("Process record: failed to record execution log."));
        }
     }
-  if (record_arch_list_add_end ())
+  if (record_full_arch_list_add_end ())
     {
       record_full_list_release (record_full_arch_list_tail);
       error (_("Process record: failed to record execution log."));
@@ -1623,19 +1566,16 @@ record_full_registers_change (struct regcache *regcache, int regnum)
   record_full_arch_list_head->prev = record_full_list;
   record_full_list = record_full_arch_list_tail;
 
-  if (record_full_insn_num == record_full_insn_max_num
-      && record_full_insn_max_num)
+  if (record_full_insn_num == record_full_insn_max_num)
     record_full_list_release_first ();
   else
     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)
     {
@@ -1655,7 +1595,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)
@@ -1667,7 +1607,7 @@ 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);
                }
@@ -1683,20 +1623,19 @@ record_full_store_registers (struct target_ops *ops,
 
       record_full_registers_change (regcache, regno);
     }
-  record_full_beneath_to_store_registers
-    (record_full_beneath_to_store_registers_ops, 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 LONGEST
-record_full_xfer_partial (struct target_ops *ops, enum target_object object,
-                         const char *annex, gdb_byte *readbuf,
-                         const gdb_byte *writebuf, ULONGEST offset,
-                         LONGEST 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
@@ -1716,43 +1655,41 @@ record_full_xfer_partial (struct target_ops *ops, enum target_object object,
        }
 
       /* Check record_full_insn_num */
-      record_full_check_insn_num (0);
+      record_full_check_insn_num ();
 
       /* Record registers change to list as an instruction.  */
       record_full_arch_list_head = NULL;
       record_full_arch_list_tail = NULL;
-      if (record_arch_list_add_mem (offset, len))
+      if (record_full_arch_list_add_mem (offset, len))
        {
          record_full_list_release (record_full_arch_list_tail);
          if (record_debug)
            fprintf_unfiltered (gdb_stdlog,
                                "Process record: failed to record "
                                "execution log.");
-         return -1;
+         return TARGET_XFER_E_IO;
        }
-      if (record_arch_list_add_end ())
+      if (record_full_arch_list_add_end ())
        {
          record_full_list_release (record_full_arch_list_tail);
          if (record_debug)
            fprintf_unfiltered (gdb_stdlog,
                                "Process record: failed to record "
                                "execution log.");
-         return -1;
+         return TARGET_XFER_E_IO;
        }
       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;
 
-      if (record_full_insn_num == record_full_insn_max_num
-         && record_full_insn_max_num)
+      if (record_full_insn_num == record_full_insn_max_num)
        record_full_list_release_first ();
       else
        record_full_insn_num++;
     }
 
-  return record_full_beneath_to_xfer_partial
-    (record_full_beneath_to_xfer_partial_ops, object, annex,
-     readbuf, writebuf, offset, len);
+  return this->beneath->xfer_partial (object, annex, readbuf, writebuf, offset,
+                                     len, xfered_len);
 }
 
 /* This structure represents a breakpoint inserted while the record
@@ -1814,12 +1751,13 @@ 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 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;
 
   if (!RECORD_FULL_IS_REPLAY)
     {
@@ -1827,20 +1765,34 @@ record_full_insert_breakpoint (struct gdbarch *gdbarch,
         really need to install regular breakpoints in the inferior.
         However, we do have to insert software single-step
         breakpoints, in case the target can't hardware step.  To keep
-        things single, we always insert.  */
-      struct cleanup *old_cleanups;
-      int ret;
+        things simple, we always insert.  */
 
-      old_cleanups = record_gdb_operation_disable_set ();
-      ret = record_full_beneath_to_insert_breakpoint (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;
     }
 
+  /* 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)
+    {
+      if (bp->addr == bp_tgt->placed_address
+         && bp->address_space == bp_tgt->placed_address_space)
+       {
+         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;
@@ -1849,11 +1801,12 @@ record_full_insert_breakpoint (struct gdbarch *gdbarch,
   return 0;
 }
 
-/* "to_remove_breakpoint" method for process record target.  */
+/* "remove_breakpoint" method for process record target.  */
 
-static int
-record_full_remove_breakpoint (struct gdbarch *gdbarch,
-                              struct bp_target_info *bp_tgt)
+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;
@@ -1868,19 +1821,20 @@ record_full_remove_breakpoint (struct gdbarch *gdbarch,
        {
          if (bp->in_target_beneath)
            {
-             struct cleanup *old_cleanups;
-             int ret;
-
-             old_cleanups = record_gdb_operation_disable_set ();
-             ret = record_full_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
-             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;
            }
 
-         VEC_unordered_remove (record_full_breakpoint_p,
-                               record_full_breakpoints, ix);
+         if (reason == REMOVE_BREAKPOINT)
+           {
+             VEC_unordered_remove (record_full_breakpoint_p,
+                                   record_full_breakpoints, ix);
+           }
          return 0;
        }
     }
@@ -1888,20 +1842,20 @@ record_full_remove_breakpoint (struct gdbarch *gdbarch,
   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 (void)
+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 (char *args, int from_tty)
+gdb_byte *
+record_full_base_target::get_bookmark (const char *args, int from_tty)
 {
-  gdb_byte *ret = NULL;
+  char *ret = NULL;
 
   /* Return stringified form of instruction count.  */
   if (record_full_list && record_full_list->type == record_full_end)
@@ -1916,67 +1870,50 @@ record_full_get_bookmark (char *args, int from_tty)
        fprintf_unfiltered (gdb_stdlog,
                            "record_full_get_bookmark returns NULL\n");
     }
-  return ret;
+  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 (gdb_byte *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;
+
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog,
                        "record_full_goto_bookmark receives %s\n", bookmark);
 
+  std::string name_holder;
   if (bookmark[0] == '\'' || bookmark[0] == '\"')
     {
       if (bookmark[strlen (bookmark) - 1] != bookmark[0])
        error (_("Unbalanced quotes: %s"), bookmark);
 
-      /* Strip trailing quote.  */
-      bookmark[strlen (bookmark) - 1] = '\0';
-      /* Strip leading quote.  */
-      bookmark++;
-      /* Pass along to cmd_record_full_goto.  */
+      name_holder = std::string (bookmark + 1, strlen (bookmark) - 2);
+      bookmark = name_holder.c_str ();
     }
 
-  cmd_record_goto ((char *) bookmark, from_tty);
-  return;
+  record_goto (bookmark);
 }
 
-static void
-record_full_async (void (*callback) (enum inferior_event_type event_type,
-                                    void *context), void *context)
+enum exec_direction_kind
+record_full_base_target::execution_direction ()
 {
-  /* If we're on top of a line target (e.g., linux-nat, remote), then
-     set it to async mode as well.  Will be NULL if we're sitting on
-     top of the core target, for "record restore".  */
-  if (record_full_beneath_to_async != NULL)
-    record_full_beneath_to_async (callback, context);
+  return record_full_execution_dir;
 }
 
-static int
-record_full_can_async_p (void)
-{
-  /* We only enable async when the user specifically asks for it.  */
-  return target_async_permitted;
-}
+/* The record_method method of target record-full.  */
 
-static int
-record_full_is_async_p (void)
+enum record_method
+record_full_base_target::record_method (ptid_t ptid)
 {
-  /* We only enable async when the user specifically asks for it.  */
-  return target_async_permitted;
+  return RECORD_METHOD_FULL;
 }
 
-static enum exec_direction_kind
-record_full_execution_direction (void)
-{
-  return record_full_execution_dir;
-}
-
-static void
-record_full_info (void)
+void
+record_full_base_target::info_record ()
 {
   struct record_full_entry *p;
 
@@ -2008,33 +1945,51 @@ record_full_info (void)
                       pulongest (record_full_insn_count));
 
       /* Display log count.  */
-      printf_filtered (_("Log contains %d instructions.\n"),
+      printf_filtered (_("Log contains %u instructions.\n"),
                       record_full_insn_num);
     }
   else
     printf_filtered (_("No instructions have been logged.\n"));
 
   /* Display max log size.  */
-  printf_filtered (_("Max logged instructions is %d.\n"),
+  printf_filtered (_("Max logged instructions is %u.\n"),
                   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 (void)
+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 (void)
+bool
+record_full_base_target::record_is_replaying (ptid_t ptid)
 {
   return RECORD_FULL_IS_REPLAY;
 }
 
+/* The "record_will_replay" target method.  */
+
+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
+     execution, this needs to be changed.  */
+
+  return RECORD_FULL_IS_REPLAY || dir == EXEC_REVERSE;
+}
+
 /* Go to a specific entry.  */
 
 static void
@@ -2059,13 +2014,14 @@ record_full_goto_entry (struct record_full_entry *p)
 
   registers_changed ();
   reinit_frame_cache ();
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+  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 (void)
+void
+record_full_base_target::goto_record_begin ()
 {
   struct record_full_entry *p = NULL;
 
@@ -2076,10 +2032,10 @@ record_full_goto_begin (void)
   record_full_goto_entry (p);
 }
 
-/* The "to_goto_record_end" target method.  */
+/* The "goto_record_end" target method.  */
 
-static void
-record_full_goto_end (void)
+void
+record_full_base_target::goto_record_end ()
 {
   struct record_full_entry *p = NULL;
 
@@ -2092,10 +2048,10 @@ record_full_goto_end (void)
   record_full_goto_entry (p);
 }
 
-/* The "to_goto_record" target method.  */
+/* The "goto_record" target method.  */
 
-static void
-record_full_goto (ULONGEST target_insn)
+void
+record_full_base_target::goto_record (ULONGEST target_insn)
 {
   struct record_full_entry *p = NULL;
 
@@ -2106,129 +2062,85 @@ record_full_goto (ULONGEST target_insn)
   record_full_goto_entry (p);
 }
 
-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_resume = record_full_resume;
-  record_full_ops.to_wait = record_full_wait;
-  record_full_ops.to_disconnect = record_full_disconnect;
-  record_full_ops.to_detach = record_full_detach;
-  record_full_ops.to_mourn_inferior = record_full_mourn_inferior;
-  record_full_ops.to_kill = record_full_kill;
-  record_full_ops.to_create_inferior = find_default_create_inferior;
-  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_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_async = record_full_async;
-  record_full_ops.to_can_async_p = record_full_can_async_p;
-  record_full_ops.to_is_async_p = record_full_is_async_p;
-  record_full_ops.to_execution_direction = record_full_execution_direction;
-  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_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.  */
+/* The "record_stop_replaying" target method.  */
 
-static void
-record_full_core_resume (struct target_ops *ops, ptid_t ptid, int step,
-                        enum gdb_signal signal)
+void
+record_full_base_target::record_stop_replaying ()
+{
+  goto_record_end ();
+}
+
+/* "resume" method for prec over corefile.  */
+
+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.  */
   if (target_can_async_p ())
-    {
-      target_async (inferior_event_handler, 0);
-
-      /* Notify the event loop there's an event to wait for.  */
-      mark_async_event_handler (record_full_async_inferior_event_token);
-    }
+    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 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 LONGEST
-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,
-                              LONGEST 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)
     {
@@ -2258,7 +2170,9 @@ record_full_core_xfer_partial (struct target_ops *ops,
                    {
                      if (readbuf)
                        memset (readbuf, 0, len);
-                     return len;
+
+                     *xfered_len = len;
+                     return TARGET_XFER_OK;
                    }
                  /* Get record_full_core_buf_entry.  */
                  for (entry = record_full_core_buf_list; entry;
@@ -2270,16 +2184,15 @@ record_full_core_xfer_partial (struct target_ops *ops,
                      if (!entry)
                        {
                          /* Add a new entry.  */
-                         entry = (struct record_full_core_buf_entry *)
-                           xmalloc
-                           (sizeof (struct record_full_core_buf_entry));
+                         entry = XNEW (struct record_full_core_buf_entry);
                          entry->p = p;
-                         if (!bfd_malloc_and_get_section (p->bfd,
-                                                          p->the_bfd_section,
-                                                          &entry->buf))
+                         if (!bfd_malloc_and_get_section
+                               (p->the_bfd_section->owner,
+                                p->the_bfd_section,
+                                &entry->buf))
                            {
                              xfree (entry);
-                             return 0;
+                             return TARGET_XFER_EOF;
                            }
                          entry->prev = record_full_core_buf_list;
                          record_full_core_buf_list = entry;
@@ -2291,99 +2204,56 @@ record_full_core_xfer_partial (struct target_ops *ops,
                  else
                    {
                      if (!entry)
-                       return record_full_beneath_to_xfer_partial
-                         (record_full_beneath_to_xfer_partial_ops,
-                          object, annex, readbuf, writebuf,
-                          offset, len);
+                       return this->beneath->xfer_partial (object, annex,
+                                                           readbuf, writebuf,
+                                                           offset, len,
+                                                           xfered_len);
 
                      memcpy (readbuf, entry->buf + sec_offset,
                              (size_t) len);
                    }
 
-                 return len;
+                 *xfered_len = len;
+                 return TARGET_XFER_OK;
                }
            }
 
-         return -1;
+         return TARGET_XFER_E_IO;
        }
       else
        error (_("You can't do that without a process to debug."));
     }
 
-  return record_full_beneath_to_xfer_partial
-    (record_full_beneath_to_xfer_partial_ops, object, annex,
-     readbuf, writebuf, offset, 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 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 gdbarch *gdbarch,
-                                   struct bp_target_info *bp_tgt)
+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 (ptid_t the_ptid)
 {
-  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_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_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_async = record_full_async;
-  record_full_core_ops.to_can_async_p = record_full_can_async_p;
-  record_full_core_ops.to_is_async_p = record_full_is_async_p;
-  record_full_core_ops.to_execution_direction
-    = record_full_execution_direction;
-  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_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
@@ -2463,16 +2333,6 @@ netorder32 (uint32_t input)
   return ret;
 }
 
-static inline uint16_t
-netorder16 (uint16_t input)
-{
-  uint16_t ret;
-
-  store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret), 
-                         BFD_ENDIAN_BIG, input);
-  return ret;
-}
-
 /* Restore the execution log from a core_bfd file.  */
 static void
 record_full_restore (void)
@@ -2596,7 +2456,7 @@ record_full_restore (void)
          bfdcore_read (core_bfd, osec, &signal, 
                        sizeof (signal), &bfd_offset);
          signal = netorder32 (signal);
-         rec->u.end.sigval = signal;
+         rec->u.end.sigval = (enum gdb_signal) signal;
 
          /* Get insn count.  */
          bfdcore_read (core_bfd, osec, &count, 
@@ -2636,7 +2496,7 @@ record_full_restore (void)
   if (record_full_insn_num > record_full_insn_max_num)
     {
       record_full_insn_max_num = record_full_insn_num;
-      warning (_("Auto increase record/replay buffer limit to %d."),
+      warning (_("Auto increase record/replay buffer limit to %u."),
                record_full_insn_max_num);
     }
 
@@ -2644,7 +2504,7 @@ record_full_restore (void)
   printf_filtered (_("Restored records from core file %s.\n"),
                   bfd_get_filename (core_bfd));
 
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
 /* bfdcore_write -- write bytes into a core file section.  */
@@ -2666,36 +2526,22 @@ 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);
 }
 
-static void
-record_full_save_cleanups (void *data)
-{
-  bfd *obfd = data;
-  char *pathname = xstrdup (bfd_get_filename (obfd));
-
-  gdb_bfd_unref (obfd);
-  unlink (pathname);
-  xfree (pathname);
-}
-
 /* 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 (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 *old_cleanups;
-  struct cleanup *set_cleanups;
-  bfd *obfd;
   int save_size = 0;
   asection *osec = NULL;
   int bfd_offset = 0;
@@ -2706,18 +2552,21 @@ record_full_save (char *recfilename)
                        recfilename);
 
   /* Open the output file.  */
-  obfd = create_gcore_bfd (recfilename);
-  old_cleanups = make_cleanup (record_full_save_cleanups, obfd);
+  gdb_bfd_ref_ptr obfd (create_gcore_bfd (recfilename));
+
+  /* Arrange to remove the output file on failure.  */
+  gdb::unlinker unlink_file (recfilename);
 
   /* Save the current record entry to "cur_record_full_list".  */
   cur_record_full_list = record_full_list;
 
   /* 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_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)
@@ -2750,20 +2599,20 @@ record_full_save (char *recfilename)
       }
 
   /* Make the new bfd section.  */
-  osec = bfd_make_section_anyway_with_flags (obfd, "precord",
+  osec = bfd_make_section_anyway_with_flags (obfd.get (), "precord",
                                              SEC_HAS_CONTENTS
                                              | SEC_READONLY);
   if (osec == NULL)
     error (_("Failed to create 'precord' section for corefile %s: %s"),
           recfilename,
            bfd_errmsg (bfd_get_error ()));
-  bfd_set_section_size (obfd, osec, save_size);
-  bfd_set_section_vma (obfd, osec, 0);
-  bfd_set_section_alignment (obfd, osec, 0);
-  bfd_section_lma (obfd, osec) = 0;
+  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;
 
   /* Save corefile state.  */
-  write_gcore_file (obfd);
+  write_gcore_file (obfd.get ());
 
   /* Write out the record log.  */
   /* Write the magic code.  */
@@ -2773,7 +2622,7 @@ record_full_save (char *recfilename)
                        "  Writing 4-byte magic cookie "
                        "RECORD_FULL_FILE_MAGIC (0x%s)\n",
                      phex_nz (magic, 4));
-  bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset);
+  bfdcore_write (obfd.get (), osec, &magic, sizeof (magic), &bfd_offset);
 
   /* Save the entries to recfd and forward execute to the end of
      record list.  */
@@ -2788,7 +2637,7 @@ record_full_save (char *recfilename)
           uint64_t addr;
 
          type = record_full_list->type;
-          bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset);
+          bfdcore_write (obfd.get (), osec, &type, sizeof (type), &bfd_offset);
 
           switch (record_full_list->type)
             {
@@ -2803,11 +2652,11 @@ record_full_save (char *recfilename)
 
               /* Write regnum.  */
               regnum = netorder32 (record_full_list->u.reg.num);
-              bfdcore_write (obfd, osec, &regnum,
+              bfdcore_write (obfd.get (), osec, &regnum,
                             sizeof (regnum), &bfd_offset);
 
               /* Write regval.  */
-              bfdcore_write (obfd, osec,
+              bfdcore_write (obfd.get (), osec,
                             record_full_get_loc (record_full_list),
                             record_full_list->u.reg.len, &bfd_offset);
               break;
@@ -2825,15 +2674,16 @@ record_full_save (char *recfilename)
 
              /* Write memlen.  */
              len = netorder32 (record_full_list->u.mem.len);
-             bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset);
+             bfdcore_write (obfd.get (), osec, &len, sizeof (len),
+                            &bfd_offset);
 
              /* Write memaddr.  */
              addr = netorder64 (record_full_list->u.mem.addr);
-             bfdcore_write (obfd, osec, &addr, 
+             bfdcore_write (obfd.get (), osec, &addr, 
                             sizeof (addr), &bfd_offset);
 
              /* Write memval.  */
-             bfdcore_write (obfd, osec,
+             bfdcore_write (obfd.get (), osec,
                             record_full_get_loc (record_full_list),
                             record_full_list->u.mem.len, &bfd_offset);
               break;
@@ -2847,12 +2697,12 @@ record_full_save (char *recfilename)
                                      (unsigned long) sizeof (count));
                /* Write signal value.  */
                signal = netorder32 (record_full_list->u.end.sigval);
-               bfdcore_write (obfd, osec, &signal,
+               bfdcore_write (obfd.get (), osec, &signal,
                               sizeof (signal), &bfd_offset);
 
                /* Write insn count.  */
                count = netorder32 (record_full_list->u.end.insn_num);
-               bfdcore_write (obfd, osec, &count,
+               bfdcore_write (obfd.get (), osec, &count,
                               sizeof (count), &bfd_offset);
                 break;
             }
@@ -2880,9 +2730,7 @@ record_full_save (char *recfilename)
         record_full_list = record_full_list->prev;
     }
 
-  do_cleanups (set_cleanups);
-  gdb_bfd_unref (obfd);
-  discard_cleanups (old_cleanups);
+  unlink_file.keep ();
 
   /* Succeeded.  */
   printf_filtered (_("Saved core file %s with execution log.\n"),
@@ -2897,9 +2745,10 @@ static void
 record_full_goto_insn (struct record_full_entry *entry,
                       enum exec_direction_kind dir)
 {
-  struct cleanup *set_cleanups = record_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.  */
@@ -2915,23 +2764,21 @@ 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 ("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
-      && record_full_insn_max_num)
+  if (record_full_insn_num > record_full_insn_max_num)
     {
       /* Count down record_full_insn_num while releasing records from list.  */
       while (record_full_insn_num > record_full_insn_max_num)
@@ -2945,10 +2792,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);
 }
@@ -2956,14 +2803,11 @@ 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, "");
 }
 
-/* Provide a prototype to silence -Wmissing-prototypes.  */
-extern initialize_file_ftype _initialize_record_full;
-
 void
 _initialize_record_full (void)
 {
@@ -2974,11 +2818,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,
@@ -3029,7 +2871,8 @@ delete the oldest recorded instruction to make room for each new one."),
                            _("Set record/replay buffer limit."),
                            _("Show record/replay buffer limit."), _("\
 Set the maximum number of instructions to be stored in the\n\
-record/replay buffer.  Zero means unlimited.  Default is 200000."),
+record/replay buffer.  A value of either \"unlimited\" or zero means no\n\
+limit.  Default is 200000."),
                            set_record_full_insn_max_num,
                            NULL, &set_record_full_cmdlist,
                            &show_record_full_cmdlist);
@@ -3043,7 +2886,7 @@ record/replay buffer.  Zero means unlimited.  Default is 200000."),
   deprecate_cmd (c, "show record full insn-number-max");
 
   add_setshow_boolean_cmd ("memory-query", no_class,
-                          &record_memory_query, _("\
+                          &record_full_memory_query, _("\
 Set whether query if PREC cannot record memory change of next instruction."),
                            _("\
 Show whether query if PREC cannot record memory change of next instruction."),
This page took 0.0527879999999999 seconds and 4 git commands to generate.