]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/record-full.c
[gdb] Fix segfault in for_each_block, part 1
[thirdparty/binutils-gdb.git] / gdb / record-full.c
index 59e4410c0085182391977b6c94bb9a74fdc9d24f..2fc9e433ca85644e56adccc394460a73e5364ec2 100644 (file)
@@ -1,6 +1,6 @@
 /* Process record and replay target for GDB, the GNU debugger.
 
-   Copyright (C) 2013-2021 Free Software Foundation, Inc.
+   Copyright (C) 2013-2023 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -39,6 +39,8 @@
 #include "gdbsupport/gdb_unlinker.h"
 #include "gdbsupport/byte-vector.h"
 #include "async-event.h"
+#include "valprint.h"
+#include "interps.h"
 
 #include <signal.h>
 
@@ -171,7 +173,7 @@ struct record_full_core_buf_entry
 
 /* Record buf with core target.  */
 static detached_regcache *record_full_core_regbuf = NULL;
-static target_section_table record_full_core_sections;
+static std::vector<target_section> record_full_core_sections;
 static struct record_full_core_buf_entry *record_full_core_buf_list = NULL;
 
 /* The following variables are used for managing the linked list that
@@ -223,7 +225,7 @@ public:
   strata stratum () const override { return record_stratum; }
 
   void close () override;
-  void async (int) override;
+  void async (bool) override;
   ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
   bool stopped_by_watchpoint () override;
   bool stopped_data_address (CORE_ADDR *) override;
@@ -565,9 +567,9 @@ static void
 record_full_arch_list_add (struct record_full_entry *rec)
 {
   if (record_debug > 1)
-    fprintf_unfiltered (gdb_stdlog,
-                       "Process record: record_full_arch_list_add %s.\n",
-                       host_address_to_string (rec));
+    gdb_printf (gdb_stdlog,
+               "Process record: record_full_arch_list_add %s.\n",
+               host_address_to_string (rec));
 
   if (record_full_arch_list_tail)
     {
@@ -612,10 +614,10 @@ record_full_arch_list_add_reg (struct regcache *regcache, int regnum)
   struct record_full_entry *rec;
 
   if (record_debug > 1)
-    fprintf_unfiltered (gdb_stdlog,
-                       "Process record: add register num = %d to "
-                       "record list.\n",
-                       regnum);
+    gdb_printf (gdb_stdlog,
+               "Process record: add register num = %d to "
+               "record list.\n",
+               regnum);
 
   rec = record_full_reg_alloc (regcache, regnum);
 
@@ -635,17 +637,17 @@ record_full_arch_list_add_mem (CORE_ADDR addr, int len)
   struct record_full_entry *rec;
 
   if (record_debug > 1)
-    fprintf_unfiltered (gdb_stdlog,
-                       "Process record: add mem addr = %s len = %d to "
-                       "record list.\n",
-                       paddress (target_gdbarch (), addr), len);
+    gdb_printf (gdb_stdlog,
+               "Process record: add mem addr = %s len = %d to "
+               "record list.\n",
+               paddress (current_inferior ()->arch (), addr), len);
 
   if (!addr)   /* FIXME: Why?  Some arch must permit it...  */
     return 0;
 
   rec = record_full_mem_alloc (addr, len);
 
-  if (record_read_memory (target_gdbarch (), addr,
+  if (record_read_memory (current_inferior ()->arch (), addr,
                          record_full_get_loc (rec), len))
     {
       record_full_mem_release (rec);
@@ -666,8 +668,8 @@ record_full_arch_list_add_end (void)
   struct record_full_entry *rec;
 
   if (record_debug > 1)
-    fprintf_unfiltered (gdb_stdlog,
-                       "Process record: add end to arch list.\n");
+    gdb_printf (gdb_stdlog,
+               "Process record: add end to arch list.\n");
 
   rec = record_full_end_alloc ();
   rec->u.end.sigval = GDB_SIGNAL_0;
@@ -784,7 +786,7 @@ record_full_message_wrapper_safe (struct regcache *regcache,
     {
       record_full_message (regcache, signal);
     }
-  catch (const gdb_exception &ex)
+  catch (const gdb_exception_error &ex)
     {
       exception_print (gdb_stderr, ex);
       return false;
@@ -824,11 +826,11 @@ record_full_exec_insn (struct regcache *regcache,
        gdb::byte_vector reg (entry->u.reg.len);
 
        if (record_debug > 1)
-         fprintf_unfiltered (gdb_stdlog,
-                             "Process record: record_full_reg %s to "
-                             "inferior num = %d.\n",
-                             host_address_to_string (entry),
-                             entry->u.reg.num);
+         gdb_printf (gdb_stdlog,
+                     "Process record: record_full_reg %s to "
+                     "inferior num = %d.\n",
+                     host_address_to_string (entry),
+                     entry->u.reg.num);
 
        regcache->cooked_read (entry->u.reg.num, reg.data ());
        regcache->cooked_write (entry->u.reg.num, record_full_get_loc (entry));
@@ -844,12 +846,12 @@ record_full_exec_insn (struct regcache *regcache,
            gdb::byte_vector mem (entry->u.mem.len);
 
            if (record_debug > 1)
-             fprintf_unfiltered (gdb_stdlog,
-                                 "Process record: record_full_mem %s to "
-                                 "inferior addr = %s len = %d.\n",
-                                 host_address_to_string (entry),
-                                 paddress (gdbarch, entry->u.mem.addr),
-                                 entry->u.mem.len);
+             gdb_printf (gdb_stdlog,
+                         "Process record: record_full_mem %s to "
+                         "inferior addr = %s len = %d.\n",
+                         host_address_to_string (entry),
+                         paddress (gdbarch, entry->u.mem.addr),
+                         entry->u.mem.len);
 
            if (record_read_memory (gdbarch,
                                    entry->u.mem.addr, mem.data (),
@@ -882,7 +884,7 @@ record_full_exec_insn (struct regcache *regcache,
                       not doing the change at all if the watchpoint
                       traps.  */
                    if (hardware_watchpoint_inserted_in_range
-                       (regcache->aspace (),
+                       (current_inferior ()->aspace.get (),
                         entry->u.mem.addr, entry->u.mem.len))
                      record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
                  }
@@ -911,7 +913,7 @@ record_full_async_inferior_event_handler (gdb_client_data data)
 static void
 record_full_core_open_1 (const char *name, int from_tty)
 {
-  struct regcache *regcache = get_current_regcache ();
+  regcache *regcache = get_thread_regcache (inferior_thread ());
   int regnum = gdbarch_num_regs (regcache->arch ());
   int i;
 
@@ -924,7 +926,7 @@ record_full_core_open_1 (const char *name, int from_tty)
 
   record_full_core_sections = build_section_table (core_bfd);
 
-  push_target (&record_full_core_ops);
+  current_inferior ()->push_target (&record_full_core_ops);
   record_full_restore ();
 }
 
@@ -934,7 +936,7 @@ static void
 record_full_open_1 (const char *name, int from_tty)
 {
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open_1\n");
+    gdb_printf (gdb_stdlog, "Process record: record_full_open_1\n");
 
   /* check exec */
   if (!target_has_execution ())
@@ -943,11 +945,11 @@ record_full_open_1 (const char *name, int from_tty)
     error (_("Process record target can't debug inferior in non-stop mode "
             "(non-stop)."));
 
-  if (!gdbarch_process_record_p (target_gdbarch ()))
+  if (!gdbarch_process_record_p (current_inferior ()->arch ()))
     error (_("Process record: the current architecture doesn't support "
             "record function."));
 
-  push_target (&record_full_ops);
+  current_inferior ()->push_target (&record_full_ops);
 }
 
 static void record_full_init_record_breakpoints (void);
@@ -958,7 +960,7 @@ static void
 record_full_open (const char *name, int from_tty)
 {
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
+    gdb_printf (gdb_stdlog, "Process record: record_full_open\n");
 
   record_preopen ();
 
@@ -980,7 +982,7 @@ record_full_open (const char *name, int from_tty)
 
   record_full_init_record_breakpoints ();
 
-  gdb::observers::record_changed.notify (current_inferior (),  1, "full", NULL);
+  interps_notify_record_changed (current_inferior (),  1, "full", NULL);
 }
 
 /* "close" target method.  Close the process record target.  */
@@ -991,7 +993,7 @@ record_full_base_target::close ()
   struct record_full_core_buf_entry *entry;
 
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: record_full_close\n");
+    gdb_printf (gdb_stdlog, "Process record: record_full_close\n");
 
   record_full_list_release (record_full_list);
 
@@ -1017,7 +1019,7 @@ record_full_base_target::close ()
 /* "async" target method.  */
 
 void
-record_full_base_target::async (int enable)
+record_full_base_target::async (bool enable)
 {
   if (enable)
     mark_async_event_handler (record_full_async_inferior_event_token);
@@ -1067,7 +1069,7 @@ record_full_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
     {
       struct gdbarch *gdbarch = target_thread_architecture (ptid);
 
-      record_full_message (get_current_regcache (), signal);
+      record_full_message (get_thread_regcache (inferior_thread ()), signal);
 
       if (!step)
        {
@@ -1093,13 +1095,15 @@ record_full_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
       /* Make sure the target beneath reports all signals.  */
       target_pass_signals ({});
 
+      /* Disable range-stepping, forcing the process target to report stops for
+        all executed instructions, so we can record them all.  */
+      process_stratum_target *proc_target
+       = current_inferior ()->process_target ();
+      for (thread_info *thread : all_non_exited_threads (proc_target, ptid))
+       thread->control.may_range_step = 0;
+
       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 (1);
 }
 
 static int record_full_get_sig = 0;
@@ -1110,7 +1114,7 @@ static void
 record_full_sig_handler (int signo)
 {
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: get a signal\n");
+    gdb_printf (gdb_stdlog, "Process record: get a signal\n");
 
   /* It will break the running inferior in replay mode.  */
   record_full_resume_step = 1;
@@ -1142,20 +1146,20 @@ record_full_wait_1 (struct target_ops *ops,
     = record_full_gdb_operation_disable_set ();
 
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog,
-                       "Process record: record_full_wait "
-                       "record_full_resume_step = %d, "
-                       "record_full_resumed = %d, direction=%s\n",
-                       record_full_resume_step, record_full_resumed,
-                       record_full_execution_dir == EXEC_FORWARD
-                       ? "forward" : "reverse");
+    gdb_printf (gdb_stdlog,
+               "Process record: record_full_wait "
+               "record_full_resume_step = %d, "
+               "record_full_resumed = %d, direction=%s\n",
+               record_full_resume_step, record_full_resumed,
+               record_full_execution_dir == EXEC_FORWARD
+               ? "forward" : "reverse");
 
   if (!record_full_resumed)
     {
       gdb_assert ((options & TARGET_WNOHANG) != 0);
 
       /* No interesting event.  */
-      status->kind = TARGET_WAITKIND_IGNORE;
+      status->set_ignore ();
       return minus_one_ptid;
     }
 
@@ -1182,12 +1186,12 @@ record_full_wait_1 (struct target_ops *ops,
          while (1)
            {
              ret = ops->beneath ()->wait (ptid, status, options);
-             if (status->kind == TARGET_WAITKIND_IGNORE)
+             if (status->kind () == TARGET_WAITKIND_IGNORE)
                {
                  if (record_debug)
-                   fprintf_unfiltered (gdb_stdlog,
-                                       "Process record: record_full_wait "
-                                       "target beneath not done yet\n");
+                   gdb_printf (gdb_stdlog,
+                               "Process record: record_full_wait "
+                               "target beneath not done yet\n");
                  return ret;
                }
 
@@ -1198,8 +1202,8 @@ record_full_wait_1 (struct target_ops *ops,
                return ret;
 
              /* Is this a SIGTRAP?  */
-             if (status->kind == TARGET_WAITKIND_STOPPED
-                 && status->value.sig == GDB_SIGNAL_TRAP)
+             if (status->kind () == TARGET_WAITKIND_STOPPED
+                 && status->sig () == GDB_SIGNAL_TRAP)
                {
                  struct regcache *regcache;
                  enum target_stop_reason *stop_reason_p
@@ -1212,9 +1216,10 @@ record_full_wait_1 (struct target_ops *ops,
                  registers_changed ();
                  switch_to_thread (current_inferior ()->process_target (),
                                    ret);
-                 regcache = get_current_regcache ();
+                 regcache = get_thread_regcache (inferior_thread ());
                  tmp_pc = regcache_read_pc (regcache);
-                 const struct address_space *aspace = regcache->aspace ();
+                 const address_space *aspace
+                   = current_inferior ()->aspace.get ();
 
                  if (target_stopped_by_watchpoint ())
                    {
@@ -1236,34 +1241,37 @@ record_full_wait_1 (struct target_ops *ops,
 
                      if (!record_full_message_wrapper_safe (regcache,
                                                             GDB_SIGNAL_0))
-                       {
-                          status->kind = TARGET_WAITKIND_STOPPED;
-                          status->value.sig = GDB_SIGNAL_0;
+                       {
+                          status->set_stopped (GDB_SIGNAL_0);
                           break;
-                       }
+                       }
+
+                     process_stratum_target *proc_target
+                       = current_inferior ()->process_target ();
 
                      if (gdbarch_software_single_step_p (gdbarch))
                        {
-                         process_stratum_target *proc_target
-                           = current_inferior ()->process_target ();
-
                          /* Try to insert the software single step breakpoint.
                             If insert success, set step to 0.  */
                          set_executing (proc_target, inferior_ptid, false);
-                         reinit_frame_cache ();
+                         SCOPE_EXIT
+                           {
+                             set_executing (proc_target, inferior_ptid, true);
+                           };
 
+                         reinit_frame_cache ();
                          step = !insert_single_step_breakpoints (gdbarch);
-
-                         set_executing (proc_target, inferior_ptid, true);
                        }
 
                      if (record_debug)
-                       fprintf_unfiltered (gdb_stdlog,
-                                           "Process record: record_full_wait "
-                                           "issuing one more step in the "
-                                           "target beneath\n");
+                       gdb_printf (gdb_stdlog,
+                                   "Process record: record_full_wait "
+                                   "issuing one more step in the "
+                                   "target beneath\n");
                      ops->beneath ()->resume (ptid, step, GDB_SIGNAL_0);
-                     ops->beneath ()->commit_resume ();
+                     proc_target->commit_resumed_state = true;
+                     proc_target->commit_resumed ();
+                     proc_target->commit_resumed_state = false;
                      continue;
                    }
                }
@@ -1279,9 +1287,9 @@ record_full_wait_1 (struct target_ops *ops,
     {
       switch_to_thread (current_inferior ()->process_target (),
                        record_full_resume_ptid);
-      struct regcache *regcache = get_current_regcache ();
+      regcache *regcache = get_thread_regcache (inferior_thread ());
       struct gdbarch *gdbarch = regcache->arch ();
-      const struct address_space *aspace = regcache->aspace ();
+      const address_space *aspace = current_inferior ()->aspace.get ();
       int continue_flag = 1;
       int first_record_full_end = 1;
 
@@ -1290,7 +1298,7 @@ record_full_wait_1 (struct target_ops *ops,
          CORE_ADDR tmp_pc;
 
          record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
-         status->kind = TARGET_WAITKIND_STOPPED;
+         status->set_stopped (GDB_SIGNAL_0);
 
          /* Check breakpoint when forward execute.  */
          if (execution_direction == EXEC_FORWARD)
@@ -1300,9 +1308,9 @@ record_full_wait_1 (struct target_ops *ops,
                                                      &record_full_stop_reason))
                {
                  if (record_debug)
-                   fprintf_unfiltered (gdb_stdlog,
-                                       "Process record: break at %s.\n",
-                                       paddress (gdbarch, tmp_pc));
+                   gdb_printf (gdb_stdlog,
+                               "Process record: break at %s.\n",
+                               paddress (gdbarch, tmp_pc));
                  goto replay_out;
                }
            }
@@ -1328,14 +1336,14 @@ record_full_wait_1 (struct target_ops *ops,
                  && record_full_list == &record_full_first)
                {
                  /* Hit beginning of record log in reverse.  */
-                 status->kind = TARGET_WAITKIND_NO_HISTORY;
+                 status->set_no_history ();
                  break;
                }
              if (execution_direction != EXEC_REVERSE
                  && !record_full_list->next)
                {
                  /* Hit end of record log going forward.  */
-                 status->kind = TARGET_WAITKIND_NO_HISTORY;
+                 status->set_no_history ();
                  break;
                }
 
@@ -1344,7 +1352,7 @@ record_full_wait_1 (struct target_ops *ops,
              if (record_full_list->type == record_full_end)
                {
                  if (record_debug > 1)
-                   fprintf_unfiltered
+                   gdb_printf
                      (gdb_stdlog,
                       "Process record: record_full_end %s to "
                       "inferior.\n",
@@ -1368,8 +1376,8 @@ record_full_wait_1 (struct target_ops *ops,
                      if (record_full_resume_step)
                        {
                          if (record_debug > 1)
-                           fprintf_unfiltered (gdb_stdlog,
-                                               "Process record: step.\n");
+                           gdb_printf (gdb_stdlog,
+                                       "Process record: step.\n");
                          continue_flag = 0;
                        }
 
@@ -1379,10 +1387,10 @@ record_full_wait_1 (struct target_ops *ops,
                          (aspace, tmp_pc, &record_full_stop_reason))
                        {
                          if (record_debug)
-                           fprintf_unfiltered (gdb_stdlog,
-                                               "Process record: break "
-                                               "at %s.\n",
-                                               paddress (gdbarch, tmp_pc));
+                           gdb_printf (gdb_stdlog,
+                                       "Process record: break "
+                                       "at %s.\n",
+                                       paddress (gdbarch, tmp_pc));
 
                          continue_flag = 0;
                        }
@@ -1391,9 +1399,9 @@ record_full_wait_1 (struct target_ops *ops,
                          == TARGET_STOPPED_BY_WATCHPOINT)
                        {
                          if (record_debug)
-                           fprintf_unfiltered (gdb_stdlog,
-                                               "Process record: hit hw "
-                                               "watchpoint.\n");
+                           gdb_printf (gdb_stdlog,
+                                       "Process record: hit hw "
+                                       "watchpoint.\n");
                          continue_flag = 0;
                        }
                      /* Check target signal */
@@ -1420,13 +1428,16 @@ record_full_wait_1 (struct target_ops *ops,
          while (continue_flag);
 
        replay_out:
-         if (record_full_get_sig)
-           status->value.sig = GDB_SIGNAL_INT;
-         else if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
-           /* FIXME: better way to check */
-           status->value.sig = record_full_list->u.end.sigval;
-         else
-           status->value.sig = GDB_SIGNAL_TRAP;
+         if (status->kind () == TARGET_WAITKIND_STOPPED)
+           {
+             if (record_full_get_sig)
+               status->set_stopped (GDB_SIGNAL_INT);
+             else if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
+               /* FIXME: better way to check */
+               status->set_stopped (record_full_list->u.end.sigval);
+             else
+               status->set_stopped (GDB_SIGNAL_TRAP);
+           }
        }
       catch (const gdb_exception &ex)
        {
@@ -1456,7 +1467,7 @@ record_full_base_target::wait (ptid_t ptid, struct target_waitstatus *status,
   clear_async_event_handler (record_full_async_inferior_event_token);
 
   return_ptid = record_full_wait_1 (this, ptid, status, options);
-  if (status->kind != TARGET_WAITKIND_IGNORE)
+  if (status->kind () != TARGET_WAITKIND_IGNORE)
     {
       /* We're reporting a stop.  Make sure any spurious
         target_wait(WNOHANG) doesn't advance the target until the
@@ -1640,7 +1651,7 @@ record_full_target::xfer_partial (enum target_object object,
          if (!query (_("Because GDB is in replay mode, writing to memory "
                        "will make the execution log unusable from this "
                        "point onward.  Write memory at address %s?"),
-                      paddress (target_gdbarch (), offset)))
+                      paddress (current_inferior ()->arch (), offset)))
            error (_("Process record canceled the operation."));
 
          /* Destroy the record from here forward.  */
@@ -1657,18 +1668,18 @@ record_full_target::xfer_partial (enum target_object object,
        {
          record_full_list_release (record_full_arch_list_tail);
          if (record_debug)
-           fprintf_unfiltered (gdb_stdlog,
-                               "Process record: failed to record "
-                               "execution log.");
+           gdb_printf (gdb_stdlog,
+                       "Process record: failed to record "
+                       "execution log.");
          return TARGET_XFER_E_IO;
        }
       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.");
+           gdb_printf (gdb_stdlog,
+                       "Process record: failed to record "
+                       "execution log.");
          return TARGET_XFER_E_IO;
        }
       record_full_list->next = record_full_arch_list_head;
@@ -1717,21 +1728,6 @@ struct record_full_breakpoint
    active.  */
 static std::vector<record_full_breakpoint> record_full_breakpoints;
 
-static void
-record_full_sync_record_breakpoints (struct bp_location *loc, void *data)
-{
-  if (loc->loc_type != bp_loc_software_breakpoint)
-      return;
-
-  if (loc->inserted)
-    {
-      record_full_breakpoints.emplace_back
-       (loc->target_info.placed_address_space,
-        loc->target_info.placed_address,
-        1);
-    }
-}
-
 /* Sync existing breakpoints to record_full_breakpoints.  */
 
 static void
@@ -1739,7 +1735,16 @@ record_full_init_record_breakpoints (void)
 {
   record_full_breakpoints.clear ();
 
-  iterate_over_bp_locations (record_full_sync_record_breakpoints);
+  for (bp_location *loc : all_bp_locations ())
+    {
+      if (loc->loc_type != bp_loc_software_breakpoint)
+       continue;
+
+      if (loc->inserted)
+       record_full_breakpoints.emplace_back
+         (loc->target_info.placed_address_space,
+          loc->target_info.placed_address, 1);
+    }
 }
 
 /* Behavior is conditional on RECORD_FULL_IS_REPLAY.  We will not actually
@@ -1847,11 +1852,11 @@ record_full_base_target::get_bookmark (const char *args, int from_tty)
   if (record_debug)
     {
       if (ret)
-       fprintf_unfiltered (gdb_stdlog,
-                           "record_full_get_bookmark returns %s\n", ret);
+       gdb_printf (gdb_stdlog,
+                   "record_full_get_bookmark returns %s\n", ret);
       else
-       fprintf_unfiltered (gdb_stdlog,
-                           "record_full_get_bookmark returns NULL\n");
+       gdb_printf (gdb_stdlog,
+                   "record_full_get_bookmark returns NULL\n");
     }
   return (gdb_byte *) ret;
 }
@@ -1865,8 +1870,8 @@ record_full_base_target::goto_bookmark (const gdb_byte *raw_bookmark,
   const char *bookmark = (const char *) raw_bookmark;
 
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog,
-                       "record_full_goto_bookmark receives %s\n", bookmark);
+    gdb_printf (gdb_stdlog,
+               "record_full_goto_bookmark receives %s\n", bookmark);
 
   std::string name_holder;
   if (bookmark[0] == '\'' || bookmark[0] == '\"')
@@ -1901,9 +1906,9 @@ record_full_base_target::info_record ()
   struct record_full_entry *p;
 
   if (RECORD_FULL_IS_REPLAY)
-    printf_filtered (_("Replay mode:\n"));
+    gdb_printf (_("Replay mode:\n"));
   else
-    printf_filtered (_("Record mode:\n"));
+    gdb_printf (_("Record mode:\n"));
 
   /* Find entry for first actual instruction in the log.  */
   for (p = record_full_first.next;
@@ -1915,28 +1920,28 @@ record_full_base_target::info_record ()
   if (p != NULL && p->type == record_full_end)
     {
       /* Display instruction number for first instruction in the log.  */
-      printf_filtered (_("Lowest recorded instruction number is %s.\n"),
-                      pulongest (p->u.end.insn_num));
+      gdb_printf (_("Lowest recorded instruction number is %s.\n"),
+                 pulongest (p->u.end.insn_num));
 
       /* If in replay mode, display where we are in the log.  */
       if (RECORD_FULL_IS_REPLAY)
-       printf_filtered (_("Current instruction number is %s.\n"),
-                        pulongest (record_full_list->u.end.insn_num));
+       gdb_printf (_("Current instruction number is %s.\n"),
+                   pulongest (record_full_list->u.end.insn_num));
 
       /* Display instruction number for last instruction in the log.  */
-      printf_filtered (_("Highest recorded instruction number is %s.\n"),
-                      pulongest (record_full_insn_count));
+      gdb_printf (_("Highest recorded instruction number is %s.\n"),
+                 pulongest (record_full_insn_count));
 
       /* Display log count.  */
-      printf_filtered (_("Log contains %u instructions.\n"),
-                      record_full_insn_num);
+      gdb_printf (_("Log contains %u instructions.\n"),
+                 record_full_insn_num);
     }
   else
-    printf_filtered (_("No instructions have been logged.\n"));
+    gdb_printf (_("No instructions have been logged.\n"));
 
   /* Display max log size.  */
-  printf_filtered (_("Max logged instructions is %u.\n"),
-                  record_full_insn_max_num);
+  gdb_printf (_("Max logged instructions is %u.\n"),
+             record_full_insn_max_num);
 }
 
 bool
@@ -1984,21 +1989,22 @@ record_full_goto_entry (struct record_full_entry *p)
     error (_("Already at target insn."));
   else if (p->u.end.insn_num > record_full_list->u.end.insn_num)
     {
-      printf_filtered (_("Go forward to insn number %s\n"),
-                      pulongest (p->u.end.insn_num));
+      gdb_printf (_("Go forward to insn number %s\n"),
+                 pulongest (p->u.end.insn_num));
       record_full_goto_insn (p, EXEC_FORWARD);
     }
   else
     {
-      printf_filtered (_("Go backward to insn number %s\n"),
-                      pulongest (p->u.end.insn_num));
+      gdb_printf (_("Go backward to insn number %s\n"),
+                 pulongest (p->u.end.insn_num));
       record_full_goto_insn (p, EXEC_REVERSE);
     }
 
   registers_changed ();
   reinit_frame_cache ();
-  inferior_thread ()->suspend.stop_pc
-    = regcache_read_pc (get_current_regcache ());
+  
+  thread_info *thr = inferior_thread ();
+  thr->set_stop_pc (regcache_read_pc (get_thread_regcache (thr)));
   print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
@@ -2063,11 +2069,6 @@ record_full_core_target::resume (ptid_t ptid, int step,
   record_full_resume_step = step;
   record_full_resumed = 1;
   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 (1);
 }
 
 /* "kill" method for prec over corefile.  */
@@ -2076,7 +2077,7 @@ void
 record_full_core_target::kill ()
 {
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Process record: record_full_core_kill\n");
+    gdb_printf (gdb_stdlog, "Process record: record_full_core_kill\n");
 
   current_inferior ()->unpush_target (this);
 }
@@ -2324,7 +2325,6 @@ record_full_restore (void)
   asection *osec;
   uint32_t osec_size;
   int bfd_offset = 0;
-  struct regcache *regcache;
 
   /* We restore the execution log from the open core bfd,
      if there is one.  */
@@ -2335,18 +2335,18 @@ record_full_restore (void)
   gdb_assert (record_full_first.next == NULL);
  
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Restoring recording from core file.\n");
+    gdb_printf (gdb_stdlog, "Restoring recording from core file.\n");
 
   /* Now need to find our special note section.  */
   osec = bfd_get_section_by_name (core_bfd, "null0");
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Find precord section %s.\n",
-                       osec ? "succeeded" : "failed");
+    gdb_printf (gdb_stdlog, "Find precord section %s.\n",
+               osec ? "succeeded" : "failed");
   if (osec == NULL)
     return;
   osec_size = bfd_section_size (osec);
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "%s", bfd_section_name (osec));
+    gdb_printf (gdb_stdlog, "%s", bfd_section_name (osec));
 
   /* Check the magic code.  */
   bfdcore_read (core_bfd, osec, &magic, sizeof (magic), &bfd_offset);
@@ -2354,10 +2354,10 @@ record_full_restore (void)
     error (_("Version mis-match or file format error in core file %s."),
           bfd_get_filename (core_bfd));
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog,
-                       "  Reading 4-byte magic cookie "
-                       "RECORD_FULL_FILE_MAGIC (0x%s)\n",
-                       phex_nz (netorder32 (magic), 4));
+    gdb_printf (gdb_stdlog,
+               "  Reading 4-byte magic cookie "
+               "RECORD_FULL_FILE_MAGIC (0x%s)\n",
+               phex_nz (netorder32 (magic), 4));
 
   /* Restore the entries in recfd into record_full_arch_list_head and
      record_full_arch_list_tail.  */
@@ -2367,7 +2367,7 @@ record_full_restore (void)
 
   try
     {
-      regcache = get_current_regcache ();
+      regcache *regcache = get_thread_regcache (inferior_thread ());
 
       while (1)
        {
@@ -2395,12 +2395,12 @@ record_full_restore (void)
                            rec->u.reg.len, &bfd_offset);
 
              if (record_debug)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "  Reading register %d (1 "
-                                   "plus %lu plus %d bytes)\n",
-                                   rec->u.reg.num,
-                                   (unsigned long) sizeof (regnum),
-                                   rec->u.reg.len);
+               gdb_printf (gdb_stdlog,
+                           "  Reading register %d (1 "
+                           "plus %lu plus %d bytes)\n",
+                           rec->u.reg.num,
+                           (unsigned long) sizeof (regnum),
+                           rec->u.reg.len);
              break;
 
            case record_full_mem: /* mem */
@@ -2421,14 +2421,14 @@ record_full_restore (void)
                            rec->u.mem.len, &bfd_offset);
 
              if (record_debug)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "  Reading memory %s (1 plus "
-                                   "%lu plus %lu plus %d bytes)\n",
-                                   paddress (get_current_arch (),
-                                             rec->u.mem.addr),
-                                   (unsigned long) sizeof (addr),
-                                   (unsigned long) sizeof (len),
-                                   rec->u.mem.len);
+               gdb_printf (gdb_stdlog,
+                           "  Reading memory %s (1 plus "
+                           "%lu plus %lu plus %d bytes)\n",
+                           paddress (get_current_arch (),
+                                     rec->u.mem.addr),
+                           (unsigned long) sizeof (addr),
+                           (unsigned long) sizeof (len),
+                           rec->u.mem.len);
              break;
 
            case record_full_end: /* end */
@@ -2448,13 +2448,13 @@ record_full_restore (void)
              rec->u.end.insn_num = count;
              record_full_insn_count = count + 1;
              if (record_debug)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "  Reading record_full_end (1 + "
-                                   "%lu + %lu bytes), offset == %s\n",
-                                   (unsigned long) sizeof (signal),
-                                   (unsigned long) sizeof (count),
-                                   paddress (get_current_arch (),
-                                             bfd_offset));
+               gdb_printf (gdb_stdlog,
+                           "  Reading record_full_end (1 + "
+                           "%lu + %lu bytes), offset == %s\n",
+                           (unsigned long) sizeof (signal),
+                           (unsigned long) sizeof (count),
+                           paddress (get_current_arch (),
+                                     bfd_offset));
              break;
 
            default:
@@ -2488,8 +2488,8 @@ record_full_restore (void)
     }
 
   /* Succeeded.  */
-  printf_filtered (_("Restored records from core file %s.\n"),
-                  bfd_get_filename (core_bfd));
+  gdb_printf (_("Restored records from core file %s.\n"),
+             bfd_get_filename (core_bfd));
 
   print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
@@ -2527,7 +2527,6 @@ 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;
   int save_size = 0;
   asection *osec = NULL;
@@ -2535,8 +2534,8 @@ record_full_base_target::save_record (const char *recfilename)
 
   /* Open the save file.  */
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "Saving execution log to core file '%s'\n",
-                       recfilename);
+    gdb_printf (gdb_stdlog, "Saving execution log to core file '%s'\n",
+               recfilename);
 
   /* Open the output file.  */
   gdb_bfd_ref_ptr obfd (create_gcore_bfd (recfilename));
@@ -2548,7 +2547,7 @@ record_full_base_target::save_record (const char *recfilename)
   cur_record_full_list = record_full_list;
 
   /* Get the values of regcache and gdbarch.  */
-  regcache = get_current_regcache ();
+  regcache *regcache = get_thread_regcache (inferior_thread ());
   gdbarch = regcache->arch ();
 
   /* Disable the GDB operation record.  */
@@ -2604,10 +2603,10 @@ record_full_base_target::save_record (const char *recfilename)
   /* Write the magic code.  */
   magic = RECORD_FULL_FILE_MAGIC;
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog,
-                       "  Writing 4-byte magic cookie "
-                       "RECORD_FULL_FILE_MAGIC (0x%s)\n",
-                     phex_nz (magic, 4));
+    gdb_printf (gdb_stdlog,
+               "  Writing 4-byte magic cookie "
+               "RECORD_FULL_FILE_MAGIC (0x%s)\n",
+               phex_nz (magic, 4));
   bfdcore_write (obfd.get (), osec, &magic, sizeof (magic), &bfd_offset);
 
   /* Save the entries to recfd and forward execute to the end of
@@ -2629,12 +2628,12 @@ record_full_base_target::save_record (const char *recfilename)
            {
            case record_full_reg: /* reg */
              if (record_debug)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "  Writing register %d (1 "
-                                   "plus %lu plus %d bytes)\n",
-                                   record_full_list->u.reg.num,
-                                   (unsigned long) sizeof (regnum),
-                                   record_full_list->u.reg.len);
+               gdb_printf (gdb_stdlog,
+                           "  Writing register %d (1 "
+                           "plus %lu plus %d bytes)\n",
+                           record_full_list->u.reg.num,
+                           (unsigned long) sizeof (regnum),
+                           record_full_list->u.reg.len);
 
              /* Write regnum.  */
              regnum = netorder32 (record_full_list->u.reg.num);
@@ -2649,14 +2648,14 @@ record_full_base_target::save_record (const char *recfilename)
 
            case record_full_mem: /* mem */
              if (record_debug)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "  Writing memory %s (1 plus "
-                                   "%lu plus %lu plus %d bytes)\n",
-                                   paddress (gdbarch,
-                                             record_full_list->u.mem.addr),
-                                   (unsigned long) sizeof (addr),
-                                   (unsigned long) sizeof (len),
-                                   record_full_list->u.mem.len);
+               gdb_printf (gdb_stdlog,
+                           "  Writing memory %s (1 plus "
+                           "%lu plus %lu plus %d bytes)\n",
+                           paddress (gdbarch,
+                                     record_full_list->u.mem.addr),
+                           (unsigned long) sizeof (addr),
+                           (unsigned long) sizeof (len),
+                           record_full_list->u.mem.len);
 
              /* Write memlen.  */
              len = netorder32 (record_full_list->u.mem.len);
@@ -2676,11 +2675,11 @@ record_full_base_target::save_record (const char *recfilename)
 
              case record_full_end:
                if (record_debug)
-                 fprintf_unfiltered (gdb_stdlog,
-                                     "  Writing record_full_end (1 + "
-                                     "%lu + %lu bytes)\n", 
-                                     (unsigned long) sizeof (signal),
-                                     (unsigned long) sizeof (count));
+                 gdb_printf (gdb_stdlog,
+                             "  Writing record_full_end (1 + "
+                             "%lu + %lu bytes)\n", 
+                             (unsigned long) sizeof (signal),
+                             (unsigned long) sizeof (count));
                /* Write signal value.  */
                signal = netorder32 (record_full_list->u.end.sigval);
                bfdcore_write (obfd.get (), osec, &signal,
@@ -2719,8 +2718,8 @@ record_full_base_target::save_record (const char *recfilename)
   unlink_file.keep ();
 
   /* Succeeded.  */
-  printf_filtered (_("Saved core file %s with execution log.\n"),
-                  recfilename);
+  gdb_printf (_("Saved core file %s with execution log.\n"),
+             recfilename);
 }
 
 /* record_full_goto_insn -- rewind the record log (forward or backward,
@@ -2733,7 +2732,7 @@ record_full_goto_insn (struct record_full_entry *entry,
 {
   scoped_restore restore_operation_disable
     = record_full_gdb_operation_disable_set ();
-  struct regcache *regcache = get_current_regcache ();
+  regcache *regcache = get_thread_regcache (inferior_thread ());
   struct gdbarch *gdbarch = regcache->arch ();
 
   /* Assume everything is valid: we will hit the entry,
@@ -2775,6 +2774,89 @@ set_record_full_insn_max_num (const char *args, int from_tty,
     }
 }
 
+/* Implement the 'maintenance print record-instruction' command.  */
+
+static void
+maintenance_print_record_instruction (const char *args, int from_tty)
+{
+  struct record_full_entry *to_print = record_full_list;
+
+  if (args != nullptr)
+    {
+      int offset = value_as_long (parse_and_eval (args));
+      if (offset > 0)
+       {
+         /* Move forward OFFSET instructions.  We know we found the
+            end of an instruction when to_print->type is record_full_end.  */
+         while (to_print->next != nullptr && offset > 0)
+           {
+             to_print = to_print->next;
+             if (to_print->type == record_full_end)
+               offset--;
+           }
+         if (offset != 0)
+           error (_("Not enough recorded history"));
+       }
+      else
+       {
+         while (to_print->prev != nullptr && offset < 0)
+           {
+             to_print = to_print->prev;
+             if (to_print->type == record_full_end)
+               offset++;
+           }
+         if (offset != 0)
+           error (_("Not enough recorded history"));
+       }
+    }
+  gdb_assert (to_print != nullptr);
+
+  gdbarch *arch = current_inferior ()->arch ();
+
+  /* Go back to the start of the instruction.  */
+  while (to_print->prev != nullptr && to_print->prev->type != record_full_end)
+    to_print = to_print->prev;
+
+  /* if we're in the first record, there are no actual instructions
+     recorded.  Warn the user and leave.  */
+  if (to_print == &record_full_first)
+    error (_("Not enough recorded history"));
+
+  while (to_print->type != record_full_end)
+    {
+      switch (to_print->type)
+       {
+         case record_full_reg:
+           {
+             type *regtype = gdbarch_register_type (arch, to_print->u.reg.num);
+             value *val
+                 = value_from_contents (regtype,
+                                        record_full_get_loc (to_print));
+             gdb_printf ("Register %s changed: ",
+                         gdbarch_register_name (arch, to_print->u.reg.num));
+             struct value_print_options opts;
+             get_user_print_options (&opts);
+             opts.raw = true;
+             value_print (val, gdb_stdout, &opts);
+             gdb_printf ("\n");
+             break;
+           }
+         case record_full_mem:
+           {
+             gdb_byte *b = record_full_get_loc (to_print);
+             gdb_printf ("%d bytes of memory at address %s changed from:",
+                         to_print->u.mem.len,
+                         print_core_address (arch, to_print->u.mem.addr));
+             for (int i = 0; i < to_print->u.mem.len; i++)
+               gdb_printf (" %02x", b[i]);
+             gdb_printf ("\n");
+             break;
+           }
+       }
+      to_print = to_print->next;
+    }
+}
+
 void _initialize_record_full ();
 void
 _initialize_record_full ()
@@ -2792,84 +2874,101 @@ _initialize_record_full ()
 
   add_prefix_cmd ("full", class_obscure, cmd_record_full_start,
                  _("Start full execution recording."), &record_full_cmdlist,
-                 "record full ", 0, &record_cmdlist);
+                 0, &record_cmdlist);
 
-  c = add_cmd ("restore", class_obscure, cmd_record_full_restore,
+  cmd_list_element *record_full_restore_cmd
+    = add_cmd ("restore", class_obscure, cmd_record_full_restore,
               _("Restore the execution log from a file.\n\
 Argument is filename.  File must be created with 'record save'."),
               &record_full_cmdlist);
-  set_cmd_completer (c, filename_completer);
+  set_cmd_completer (record_full_restore_cmd, filename_completer);
 
   /* Deprecate the old version without "full" prefix.  */
-  c = add_alias_cmd ("restore", "full restore", class_obscure, 1,
+  c = add_alias_cmd ("restore", record_full_restore_cmd, class_obscure, 1,
                     &record_cmdlist);
   set_cmd_completer (c, filename_completer);
   deprecate_cmd (c, "record full restore");
 
-  add_basic_prefix_cmd ("full", class_support,
-                       _("Set record options."), &set_record_full_cmdlist,
-                       "set record full ", 0, &set_record_cmdlist);
-
-  add_show_prefix_cmd ("full", class_support,
-                      _("Show record options."), &show_record_full_cmdlist,
-                      "show record full ", 0, &show_record_cmdlist);
+  add_setshow_prefix_cmd ("full", class_support,
+                         _("Set record options."),
+                         _("Show record options."),
+                         &set_record_full_cmdlist,
+                         &show_record_full_cmdlist,
+                         &set_record_cmdlist,
+                         &show_record_cmdlist);
 
   /* Record instructions number limit command.  */
-  add_setshow_boolean_cmd ("stop-at-limit", no_class,
-                          &record_full_stop_at_limit, _("\
+  set_show_commands set_record_full_stop_at_limit_cmds
+    = add_setshow_boolean_cmd ("stop-at-limit", no_class,
+                              &record_full_stop_at_limit, _("\
 Set whether record/replay stops when record/replay buffer becomes full."), _("\
 Show whether record/replay stops when record/replay buffer becomes full."),
                           _("Default is ON.\n\
 When ON, if the record/replay buffer becomes full, ask user what to do.\n\
 When OFF, if the record/replay buffer becomes full,\n\
 delete the oldest recorded instruction to make room for each new one."),
-                          NULL, NULL,
-                          &set_record_full_cmdlist, &show_record_full_cmdlist);
+                              NULL, NULL,
+                              &set_record_full_cmdlist,
+                              &show_record_full_cmdlist);
 
-  c = add_alias_cmd ("stop-at-limit", "full stop-at-limit", no_class, 1,
+  c = add_alias_cmd ("stop-at-limit",
+                    set_record_full_stop_at_limit_cmds.set, no_class, 1,
                     &set_record_cmdlist);
   deprecate_cmd (c, "set record full stop-at-limit");
 
-  c = add_alias_cmd ("stop-at-limit", "full stop-at-limit", no_class, 1,
+  c = add_alias_cmd ("stop-at-limit",
+                    set_record_full_stop_at_limit_cmds.show, no_class, 1,
                     &show_record_cmdlist);
   deprecate_cmd (c, "show record full stop-at-limit");
 
-  add_setshow_uinteger_cmd ("insn-number-max", no_class,
-                           &record_full_insn_max_num,
-                           _("Set record/replay buffer limit."),
-                           _("Show record/replay buffer limit."), _("\
+  set_show_commands record_full_insn_number_max_cmds
+    = add_setshow_uinteger_cmd ("insn-number-max", no_class,
+                               &record_full_insn_max_num,
+                               _("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.  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);
+                               set_record_full_insn_max_num,
+                               NULL, &set_record_full_cmdlist,
+                               &show_record_full_cmdlist);
 
-  c = add_alias_cmd ("insn-number-max", "full insn-number-max", no_class, 1,
-                    &set_record_cmdlist);
+  c = add_alias_cmd ("insn-number-max", record_full_insn_number_max_cmds.set,
+                    no_class, 1, &set_record_cmdlist);
   deprecate_cmd (c, "set record full insn-number-max");
 
-  c = add_alias_cmd ("insn-number-max", "full insn-number-max", no_class, 1,
-                    &show_record_cmdlist);
+  c = add_alias_cmd ("insn-number-max", record_full_insn_number_max_cmds.show,
+                    no_class, 1, &show_record_cmdlist);
   deprecate_cmd (c, "show record full insn-number-max");
 
-  add_setshow_boolean_cmd ("memory-query", no_class,
-                          &record_full_memory_query, _("\
+  set_show_commands record_full_memory_query_cmds
+    = add_setshow_boolean_cmd ("memory-query", no_class,
+                              &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."),
-                          _("\
+                              _("\
 Default is OFF.\n\
 When ON, query if PREC cannot record memory change of next instruction."),
-                          NULL, NULL,
-                          &set_record_full_cmdlist,
-                          &show_record_full_cmdlist);
+                              NULL, NULL,
+                              &set_record_full_cmdlist,
+                              &show_record_full_cmdlist);
 
-  c = add_alias_cmd ("memory-query", "full memory-query", no_class, 1,
-                    &set_record_cmdlist);
+  c = add_alias_cmd ("memory-query", record_full_memory_query_cmds.set,
+                    no_class, 1, &set_record_cmdlist);
   deprecate_cmd (c, "set record full memory-query");
 
-  c = add_alias_cmd ("memory-query", "full memory-query", no_class, 1,
-                    &show_record_cmdlist);
+  c = add_alias_cmd ("memory-query", record_full_memory_query_cmds.show,
+                    no_class, 1,&show_record_cmdlist);
   deprecate_cmd (c, "show record full memory-query");
+
+  add_cmd ("record-instruction", class_maintenance,
+          maintenance_print_record_instruction,
+          _("\
+Print a recorded instruction.\n\
+If no argument is provided, print the last instruction recorded.\n\
+If a negative argument is given, prints how the nth previous \
+instruction will be undone.\n\
+If a positive argument is given, prints \
+how the nth following instruction will be redone."), &maintenanceprintlist);
 }