]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/record-full.c
Constify add_prefix_cmd
[thirdparty/binutils-gdb.git] / gdb / record-full.c
index 14f440093044f3b8b75bbc23d365f710ea2537fb..37836e75d09e3b32d042df6815bfa6be4143da6f 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-2017 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"
@@ -35,6 +34,9 @@
 #include "inf-loop.h"
 #include "gdb_bfd.h"
 #include "observer.h"
+#include "infrun.h"
+#include "common/gdb_unlinker.h"
+#include "common/byte-vector.h"
 
 #include <signal.h>
 
@@ -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
 {
@@ -199,7 +201,7 @@ 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;
@@ -208,6 +210,19 @@ static ULONGEST record_full_insn_count;
 static struct target_ops record_full_ops;
 static struct target_ops record_full_core_ops;
 
+/* 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;
 static struct cmd_list_element *show_record_full_cmdlist;
@@ -215,43 +230,10 @@ 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);
+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.  */
@@ -264,7 +246,7 @@ record_full_reg_alloc (struct regcache *regcache, int regnum)
   struct record_full_entry *rec;
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
 
-  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 +274,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 +302,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 +465,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 +488,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 +519,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 +537,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,7 +565,7 @@ 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;
@@ -607,7 +577,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 +629,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 +658,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 +681,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 +690,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 +702,8 @@ 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 *mem = (gdb_byte *) xmalloc (entry->u.mem.len);
+            struct cleanup *cleanup = make_cleanup (xfree, mem);
 
             if (record_debug > 1)
               fprintf_unfiltered (gdb_stdlog,
@@ -791,43 +745,17 @@ record_full_exec_insn (struct regcache *regcache,
                    if (hardware_watchpoint_inserted_in_range
                        (get_regcache_aspace (regcache),
                         entry->u.mem.addr, entry->u.mem.len))
-                     record_full_hw_watchpoint = 1;
+                     record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
                  }
               }
+
+           do_cleanups (cleanup);
           }
       }
       break;
     }
 }
 
-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
@@ -844,7 +772,7 @@ record_full_async_inferior_event_handler (gdb_client_data data)
 /* Open the process record target.  */
 
 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));
@@ -852,7 +780,7 @@ record_full_core_open_1 (char *name, int from_tty)
 
   /* Get record_full_core_regbuf.  */
   target_fetch_registers (regcache, -1);
-  record_full_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum);
+  record_full_core_regbuf = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE * regnum);
   for (i = 0; i < regnum; i ++)
     regcache_raw_collect (regcache, i,
                          record_full_core_regbuf + MAX_REGISTER_SIZE * i);
@@ -874,10 +802,10 @@ record_full_core_open_1 (char *name, int from_tty)
 /* "to_open" target method 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,26 +818,6 @@ 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);
 }
 
@@ -918,69 +826,14 @@ static void record_full_init_record_breakpoints (void);
 /* "to_open" target method.  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 +841,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 +853,13 @@ record_full_open (char *name, int from_tty)
 
   record_full_init_record_breakpoints ();
 
-  observer_notify_record_changed (current_inferior (),  1);
+  observer_notify_record_changed (current_inferior (),  1, "full", NULL);
 }
 
 /* "to_close" target method.  Close the process record target.  */
 
 static void
-record_full_close (int quitting)
+record_full_close (struct target_ops *self)
 {
   struct record_full_core_buf_entry *entry;
 
@@ -1053,6 +891,19 @@ record_full_close (int quitting)
     delete_async_event_handler (&record_full_async_inferior_event_token);
 }
 
+/* "to_async" target method.  */
+
+static void
+record_full_async (struct target_ops *ops, 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);
+}
+
 static int record_full_resume_step = 0;
 
 /* True if we've been resumed, and so each record_full_wait call should
@@ -1102,43 +953,36 @@ 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);
+      ops->beneath->to_resume (ops->beneath, 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);
+}
+
+/* "to_commit_resume" method for process record target.  */
+
+static void
+record_full_commit_resume (struct target_ops *ops)
+{
+  if (!RECORD_FULL_IS_REPLAY)
+    ops->beneath->to_commit_resume (ops->beneath);
 }
 
 static int record_full_get_sig = 0;
@@ -1189,7 +1033,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 +1057,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->to_wait (ops->beneath, ptid, status, options);
        }
       else
        {
@@ -1229,8 +1075,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->to_wait (ops->beneath, ptid, status, options);
              if (status->kind == TARGET_WAITKIND_IGNORE)
                {
                  if (record_debug)
@@ -1240,8 +1087,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;
@@ -1252,6 +1099,8 @@ record_full_wait_1 (struct target_ops *ops,
                {
                  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
@@ -1266,20 +1115,11 @@ record_full_wait_1 (struct target_ops *ops,
                    {
                      /* 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 +1143,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 +1154,9 @@ 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->to_resume (ops->beneath, ptid, step,
+                                              GDB_SIGNAL_0);
+                     ops->beneath->to_commit_resume (ops->beneath);
                      continue;
                    }
                }
@@ -1339,27 +1179,20 @@ record_full_wait_1 (struct target_ops *ops,
        = 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 +1201,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 +1260,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,7 +1317,6 @@ replay_out:
 
   signal (SIGINT, handle_sigint);
 
-  do_cleanups (set_cleanups);
   return inferior_ptid;
 }
 
@@ -1515,71 +1339,55 @@ record_full_wait (struct target_ops *ops,
 }
 
 static int
-record_full_stopped_by_watchpoint (void)
+record_full_stopped_by_watchpoint (struct target_ops *ops)
 {
   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 ops->beneath->to_stopped_by_watchpoint (ops->beneath);
 }
 
-/* "to_disconnect" method for process record target.  */
-
-static void
-record_full_disconnect (struct target_ops *target, char *args, int from_tty)
+static int
+record_full_stopped_data_address (struct target_ops *ops, 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 0;
+  else
+    return ops->beneath->to_stopped_data_address (ops->beneath, addr_p);
 }
 
-/* "to_detach" method for process record target.  */
+/* The to_stopped_by_sw_breakpoint method of target record-full.  */
 
-static void
-record_full_detach (struct target_ops *ops, char *args, int from_tty)
+static int
+record_full_stopped_by_sw_breakpoint (struct target_ops *ops)
 {
-  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 to_supports_stopped_by_sw_breakpoint method of target
+   record-full.  */
 
-static void
-record_full_mourn_inferior (struct target_ops *ops)
+static int
+record_full_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
 {
-  if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: "
-                                   "record_full_mourn_inferior\n");
-
-  unpush_target (&record_full_ops);
-  target_mourn_inferior ();
+  return 1;
 }
 
-/* Close process record target before killing the inferior process.  */
+/* The to_stopped_by_hw_breakpoint method of target record-full.  */
 
-static void
-record_full_kill (struct target_ops *ops)
+static int
+record_full_stopped_by_hw_breakpoint (struct target_ops *ops)
 {
-  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;
 }
 
+/* The to_supports_stopped_by_sw_breakpoint method of target
+   record-full.  */
+
 static int
-record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+record_full_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
 {
-  if (RECORD_FULL_IS_REPLAY)
-    return 0;
-  else
-    return record_full_beneath_to_stopped_data_address (ops, addr_p);
+  return 1;
 }
 
 /* Record registers change (by user or by GDB) to list as an instruction.  */
@@ -1588,7 +1396,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;
@@ -1599,7 +1407,7 @@ record_full_registers_change (struct regcache *regcache, int regnum)
 
       for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); 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 +1416,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,8 +1431,7 @@ 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++;
@@ -1683,8 +1490,7 @@ 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);
+  ops->beneath->to_store_registers (ops->beneath, regcache, regno);
 }
 
 /* "to_xfer_partial" method.  Behavior is conditional on
@@ -1692,11 +1498,11 @@ record_full_store_registers (struct target_ops *ops,
    In replay mode, we cannot write memory unles we are willing to
    invalidate the record/replay log from this point forward.  */
 
-static LONGEST
+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,
-                         LONGEST len)
+                         ULONGEST len, ULONGEST *xfered_len)
 {
   if (!record_full_gdb_operation_disable
       && (object == TARGET_OBJECT_MEMORY
@@ -1716,43 +1522,42 @@ 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 ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+                                       readbuf, writebuf, offset,
+                                       len, xfered_len);
 }
 
 /* This structure represents a breakpoint inserted while the record
@@ -1815,11 +1620,13 @@ record_full_init_record_breakpoints (void)
    when recording.  */
 
 static int
-record_full_insert_breakpoint (struct gdbarch *gdbarch,
+record_full_insert_breakpoint (struct target_ops *ops,
+                              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,13 +1634,12 @@ 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;
+        things simple, we always insert.  */
       int ret;
 
-      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 ();
+      ret = ops->beneath->to_insert_breakpoint (ops->beneath, gdbarch, bp_tgt);
 
       if (ret != 0)
        return ret;
@@ -1841,6 +1647,22 @@ record_full_insert_breakpoint (struct gdbarch *gdbarch,
       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;
@@ -1852,8 +1674,10 @@ record_full_insert_breakpoint (struct gdbarch *gdbarch,
 /* "to_remove_breakpoint" method for process record target.  */
 
 static int
-record_full_remove_breakpoint (struct gdbarch *gdbarch,
-                              struct bp_target_info *bp_tgt)
+record_full_remove_breakpoint (struct target_ops *ops,
+                              struct gdbarch *gdbarch,
+                              struct bp_target_info *bp_tgt,
+                              enum remove_bp_reason reason)
 {
   struct record_full_breakpoint *bp;
   int ix;
@@ -1868,19 +1692,21 @@ 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 ();
+             ret = ops->beneath->to_remove_breakpoint (ops->beneath, 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;
        }
     }
@@ -1891,7 +1717,7 @@ record_full_remove_breakpoint (struct gdbarch *gdbarch,
 /* "to_can_execute_reverse" method for process record target.  */
 
 static int
-record_full_can_execute_reverse (void)
+record_full_can_execute_reverse (struct target_ops *self)
 {
   return 1;
 }
@@ -1899,9 +1725,10 @@ record_full_can_execute_reverse (void)
 /* "to_get_bookmark" method for process record and prec over core.  */
 
 static gdb_byte *
-record_full_get_bookmark (char *args, int from_tty)
+record_full_get_bookmark (struct target_ops *self, 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 +1743,56 @@ 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.  */
 
 static void
-record_full_goto_bookmark (gdb_byte *bookmark, int from_tty)
+record_full_goto_bookmark (struct target_ops *self,
+                          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);
 
   if (bookmark[0] == '\'' || bookmark[0] == '\"')
     {
+      char *copy;
+
       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.  */
+
+      copy = savestring (bookmark + 1, strlen (bookmark) - 2);
+      make_cleanup (xfree, copy);
+      bookmark = copy;
     }
 
-  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)
-{
-  /* 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);
+  do_cleanups (cleanup);
 }
 
-static int
-record_full_can_async_p (void)
+static enum exec_direction_kind
+record_full_execution_direction (struct target_ops *self)
 {
-  /* We only enable async when the user specifically asks for it.  */
-  return target_async_permitted;
+  return record_full_execution_dir;
 }
 
-static int
-record_full_is_async_p (void)
-{
-  /* We only enable async when the user specifically asks for it.  */
-  return target_async_permitted;
-}
+/* The to_record_method method of target record-full.  */
 
-static enum exec_direction_kind
-record_full_execution_direction (void)
+enum record_method
+record_full_record_method (struct target_ops *self, ptid_t ptid)
 {
-  return record_full_execution_dir;
+  return RECORD_METHOD_FULL;
 }
 
 static void
-record_full_info (void)
+record_full_info (struct target_ops *self)
 {
   struct record_full_entry *p;
 
@@ -2008,21 +1824,21 @@ 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.  */
 
 static void
-record_full_delete (void)
+record_full_delete (struct target_ops *self)
 {
   record_full_list_release_following (record_full_list);
 }
@@ -2030,11 +1846,23 @@ record_full_delete (void)
 /* The "to_record_is_replaying" target method.  */
 
 static int
-record_full_is_replaying (void)
+record_full_is_replaying (struct target_ops *self, ptid_t ptid)
 {
   return RECORD_FULL_IS_REPLAY;
 }
 
+/* The "to_record_will_replay" target method.  */
+
+static int
+record_full_will_replay (struct target_ops *self, 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 +1887,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.  */
 
 static void
-record_full_goto_begin (void)
+record_full_goto_begin (struct target_ops *self)
 {
   struct record_full_entry *p = NULL;
 
@@ -2079,7 +1908,7 @@ record_full_goto_begin (void)
 /* The "to_goto_record_end" target method.  */
 
 static void
-record_full_goto_end (void)
+record_full_goto_end (struct target_ops *self)
 {
   struct record_full_entry *p = NULL;
 
@@ -2095,7 +1924,7 @@ record_full_goto_end (void)
 /* The "to_goto_record" target method.  */
 
 static void
-record_full_goto (ULONGEST target_insn)
+record_full_goto (struct target_ops *self, ULONGEST target_insn)
 {
   struct record_full_entry *p = NULL;
 
@@ -2106,6 +1935,14 @@ record_full_goto (ULONGEST target_insn)
   record_full_goto_entry (p);
 }
 
+/* The "to_record_stop_replaying" target method.  */
+
+static void
+record_full_stop_replaying (struct target_ops *self)
+{
+  record_full_goto_end (self);
+}
+
 static void
 init_record_full_ops (void)
 {
@@ -2115,32 +1952,41 @@ init_record_full_ops (void)
     "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_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_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_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_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;
@@ -2160,12 +2006,7 @@ record_full_core_resume (struct target_ops *ops, ptid_t ptid, int step,
   /* 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.  */
@@ -2203,7 +2044,8 @@ record_full_core_fetch_registers (struct target_ops *ops,
 /* "to_prepare_to_store" method for prec over corefile.  */
 
 static void
-record_full_core_prepare_to_store (struct regcache *regcache)
+record_full_core_prepare_to_store (struct target_ops *self,
+                                  struct regcache *regcache)
 {
 }
 
@@ -2223,12 +2065,12 @@ record_full_core_store_registers (struct target_ops *ops,
 
 /* "to_xfer_partial" method for prec over corefile.  */
 
-static LONGEST
+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,
-                              LONGEST len)
+                              ULONGEST len, ULONGEST *xfered_len)
 {
   if (object == TARGET_OBJECT_MEMORY)
     {
@@ -2258,7 +2100,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 +2114,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,34 +2134,37 @@ 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 ops->beneath->to_xfer_partial (ops->beneath,
+                                                             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 ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+                                       readbuf, writebuf, offset, len,
+                                       xfered_len);
 }
 
 /* "to_insert_breakpoint" method for prec over corefile.  */
 
 static int
-record_full_core_insert_breakpoint (struct gdbarch *gdbarch,
+record_full_core_insert_breakpoint (struct target_ops *ops,
+                                   struct gdbarch *gdbarch,
                                    struct bp_target_info *bp_tgt)
 {
   return 0;
@@ -2327,8 +2173,10 @@ record_full_core_insert_breakpoint (struct gdbarch *gdbarch,
 /* "to_remove_breakpoint" method for prec over corefile.  */
 
 static int
-record_full_core_remove_breakpoint (struct gdbarch *gdbarch,
-                                   struct bp_target_info *bp_tgt)
+record_full_core_remove_breakpoint (struct target_ops *ops,
+                                   struct gdbarch *gdbarch,
+                                   struct bp_target_info *bp_tgt,
+                                   enum remove_bp_reason reason)
 {
   return 0;
 }
@@ -2350,6 +2198,7 @@ init_record_full_core_ops (void)
     "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;
@@ -2365,6 +2214,14 @@ init_record_full_core_ops (void)
     = 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;
@@ -2372,14 +2229,13 @@ init_record_full_core_ops (void)
   /* 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_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;
@@ -2463,16 +2319,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 +2442,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 +2482,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 +2490,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 +2512,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)
+record_full_save (struct target_ops *self, 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,8 +2538,10 @@ 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;
@@ -2717,7 +2551,8 @@ record_full_save (char *recfilename)
   gdbarch = get_regcache_arch (regcache);
 
   /* 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 +2585,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 +2608,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 +2623,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 +2638,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 +2660,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 +2683,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 +2716,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,7 +2731,8 @@ 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);
 
@@ -2915,23 +2750,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);
+  execute_command ((char *) "target record-full", from_tty);
 }
 
 static void
 set_record_full_insn_max_num (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 +2778,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 +2789,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)
 {
@@ -3029,7 +2859,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 +2874,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."),