]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/record.c
gdb/
[thirdparty/binutils-gdb.git] / gdb / record.c
index cd64c7adf55fe2aefcd86ad67515028abf259fe2..bb0fe5224f643d9ec65b3646984475e1065c0623 100644 (file)
@@ -1,6 +1,6 @@
 /* Process record and replay target for GDB, the GNU debugger.
 
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008-2012 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -30,6 +30,8 @@
 #include "record.h"
 #include "elf-bfd.h"
 #include "gcore.h"
+#include "event-loop.h"
+#include "inf-loop.h"
 
 #include <signal.h>
 
@@ -98,7 +100,7 @@ struct record_reg_entry
 
 struct record_end_entry
 {
-  enum target_signal sigval;
+  enum gdb_signal sigval;
   ULONGEST insn_num;
 };
 
@@ -207,7 +209,7 @@ static struct target_ops record_core_ops;
 /* The beneath function pointers.  */
 static struct target_ops *record_beneath_to_resume_ops;
 static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, int,
-                                         enum target_signal);
+                                         enum gdb_signal);
 static struct target_ops *record_beneath_to_wait_ops;
 static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t,
                                         struct target_waitstatus *,
@@ -231,6 +233,7 @@ static int (*record_beneath_to_remove_breakpoint) (struct gdbarch *,
 static int (*record_beneath_to_stopped_by_watchpoint) (void);
 static int (*record_beneath_to_stopped_data_address) (struct target_ops *,
                                                      CORE_ADDR *);
+static void (*record_beneath_to_async) (void (*) (enum inferior_event_type, void *), void *);
 
 /* Alloc and free functions for record_reg, record_mem, and record_end 
    entries.  */
@@ -454,7 +457,7 @@ record_get_loc (struct record_entry *rec)
       return rec->u.reg.u.buf;
   case record_end:
   default:
-    gdb_assert (0);
+    gdb_assert_not_reached ("unexpected record_entry type");
     return NULL;
   }
 }
@@ -495,7 +498,7 @@ record_arch_list_add_mem (CORE_ADDR addr, int len)
                        "record list.\n",
                        paddress (target_gdbarch, addr), len);
 
-  if (!addr)   /* FIXME: Why?  Some arch must permit it... */
+  if (!addr)   /* FIXME: Why?  Some arch must permit it...  */
     return 0;
 
   rec = record_mem_alloc (addr, len);
@@ -528,7 +531,7 @@ record_arch_list_add_end (void)
                        "Process record: add end to arch list.\n");
 
   rec = record_end_alloc ();
-  rec->u.end.sigval = TARGET_SIGNAL_0;
+  rec->u.end.sigval = GDB_SIGNAL_0;
   rec->u.end.insn_num = ++record_insn_count;
 
   record_arch_list_add (rec);
@@ -578,7 +581,7 @@ record_arch_list_cleanups (void *ignore)
    record_arch_list, and add it to record_list.  */
 
 static int
-record_message (struct regcache *regcache, enum target_signal signal)
+record_message (struct regcache *regcache, enum gdb_signal signal)
 {
   int ret;
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
@@ -618,7 +621,7 @@ record_message (struct regcache *regcache, enum target_signal signal)
       record_list->u.end.sigval = signal;
     }
 
-  if (signal == TARGET_SIGNAL_0
+  if (signal == GDB_SIGNAL_0
       || !gdbarch_process_record_signal_p (gdbarch))
     ret = gdbarch_process_record (gdbarch,
                                  regcache,
@@ -649,7 +652,7 @@ record_message (struct regcache *regcache, enum target_signal signal)
 
 struct record_message_args {
   struct regcache *regcache;
-  enum target_signal signal;
+  enum gdb_signal signal;
 };
 
 static int
@@ -662,7 +665,7 @@ record_message_wrapper (void *args)
 
 static int
 record_message_wrapper_safe (struct regcache *regcache,
-                             enum target_signal signal)
+                             enum gdb_signal signal)
 {
   struct record_message_args args;
 
@@ -739,8 +742,8 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
               {
                 entry->u.mem.mem_entry_not_accessible = 1;
                 if (record_debug)
-                  warning ("Process record: error reading memory at "
-                          "addr = %s len = %d.",
+                  warning (_("Process record: error reading memory at "
+                            "addr = %s len = %d."),
                            paddress (gdbarch, entry->u.mem.addr),
                            entry->u.mem.len);
               }
@@ -752,8 +755,8 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
                   {
                     entry->u.mem.mem_entry_not_accessible = 1;
                     if (record_debug)
-                      warning ("Process record: error writing memory at "
-                              "addr = %s len = %d.",
+                      warning (_("Process record: error writing memory at "
+                                "addr = %s len = %d."),
                                paddress (gdbarch, entry->u.mem.addr),
                                entry->u.mem.len);
                   }
@@ -783,7 +786,7 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
 
 static struct target_ops *tmp_to_resume_ops;
 static void (*tmp_to_resume) (struct target_ops *, ptid_t, int,
-                             enum target_signal);
+                             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 *,
@@ -806,9 +809,22 @@ 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_restore (void);
 
+/* Asynchronous signal handle registered as event loop source for when
+   we have pending events ready to be passed to the core.  */
+
+static struct async_event_handler *record_async_inferior_event_token;
+
+static void
+record_async_inferior_event_handler (gdb_client_data data)
+{
+  inferior_event_handler (INF_REG_EVENT, NULL);
+}
+
 /* Open the process record target.  */
 
 static void
@@ -852,9 +868,6 @@ record_open_1 (char *name, int from_tty)
   if (non_stop)
     error (_("Process record target can't debug inferior in non-stop mode "
             "(non-stop)."));
-  if (target_async_permitted)
-    error (_("Process record target can't debug inferior in asynchronous "
-            "mode (target-async)."));
 
   if (!gdbarch_process_record_p (target_gdbarch))
     error (_("Process record: the current architecture doesn't support "
@@ -865,19 +878,26 @@ record_open_1 (char *name, int from_tty)
   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."));
+    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."));
+    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."));
+    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."));
+    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."));
+    error (_("Could not find 'to_stopped_data_address' "
+            "method on the target stack."));
 
   push_target (&record_ops);
 }
 
+static void record_init_record_breakpoints (void);
+
 /* "to_open" target method.  Open the process record target.  */
 
 static void
@@ -906,6 +926,7 @@ record_open (char *name, int from_tty)
   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)
@@ -938,6 +959,8 @@ record_open (char *name, int from_tty)
        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."));
@@ -961,11 +984,19 @@ record_open (char *name, int from_tty)
   record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
   record_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint;
   record_beneath_to_stopped_data_address = tmp_to_stopped_data_address;
+  record_beneath_to_async = tmp_to_async;
 
-  if (current_target.to_stratum == core_stratum)
+  if (core_bfd)
     record_core_open_1 (name, from_tty);
   else
     record_open_1 (name, from_tty);
+
+  /* Register extra event sources in the event loop.  */
+  record_async_inferior_event_token
+    = create_async_event_handler (record_async_inferior_event_handler,
+                                 NULL);
+
+  record_init_record_breakpoints ();
 }
 
 /* "to_close" target method.  Close the process record target.  */
@@ -997,17 +1028,43 @@ record_close (int quitting)
        }
       record_core_buf_list = NULL;
     }
+
+  if (record_async_inferior_event_token)
+    delete_async_event_handler (&record_async_inferior_event_token);
 }
 
 static int record_resume_step = 0;
 
+/* True if we've been resumed, and so each record_wait call should
+   advance execution.  If this is false, record_wait will return a
+   TARGET_WAITKIND_IGNORE.  */
+static int record_resumed = 0;
+
+/* The execution direction of the last resume we got.  This is
+   necessary for async mode.  Vis (order is not strictly accurate):
+
+   1. user has the global execution direction set to forward
+   2. user does a reverse-step command
+   3. record_resume is called with global execution direction
+      temporarily switched to reverse
+   4. GDB's execution direction is reverted back to forward
+   5. target record notifies event loop there's an event to handle
+   6. infrun asks the target which direction was it going, and switches
+      the global execution direction accordingly (to reverse)
+   7. infrun polls an event out of the record target, and handles it
+   8. GDB goes back to the event loop, and goto #4.
+*/
+static enum exec_direction_kind record_execution_dir = EXEC_FORWARD;
+
 /* "to_resume" target method.  Resume the process record target.  */
 
 static void
 record_resume (struct target_ops *ops, ptid_t ptid, int step,
-               enum target_signal signal)
+               enum gdb_signal signal)
 {
   record_resume_step = step;
+  record_resumed = 1;
+  record_execution_dir = execution_direction;
 
   if (!RECORD_IS_REPLAY)
     {
@@ -1049,6 +1106,16 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step,
       record_beneath_to_resume (record_beneath_to_resume_ops,
                                 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_wait.  */
+      mark_async_event_handler (record_async_inferior_event_token);
+    }
 }
 
 static int record_get_sig = 0;
@@ -1095,17 +1162,27 @@ record_wait_cleanups (void *ignore)
    where to stop.  */
 
 static ptid_t
-record_wait (struct target_ops *ops,
-            ptid_t ptid, struct target_waitstatus *status,
-            int options)
+record_wait_1 (struct target_ops *ops,
+              ptid_t ptid, struct target_waitstatus *status,
+              int options)
 {
   struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
 
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog,
                        "Process record: record_wait "
-                       "record_resume_step = %d\n",
-                       record_resume_step);
+                       "record_resume_step = %d, record_resumed = %d, direction=%s\n",
+                       record_resume_step, record_resumed,
+                       record_execution_dir == EXEC_FORWARD ? "forward" : "reverse");
+
+  if (!record_resumed)
+    {
+      gdb_assert ((options & TARGET_WNOHANG) != 0);
+
+      /* No interesting event.  */
+      status->kind = TARGET_WAITKIND_IGNORE;
+      return minus_one_ptid;
+    }
 
   record_get_sig = 0;
   signal (SIGINT, record_sig_handler);
@@ -1129,16 +1206,24 @@ record_wait (struct target_ops *ops,
            {
              ret = record_beneath_to_wait (record_beneath_to_wait_ops,
                                            ptid, status, options);
+             if (status->kind == TARGET_WAITKIND_IGNORE)
+               {
+                 if (record_debug)
+                   fprintf_unfiltered (gdb_stdlog,
+                                       "Process record: record_wait "
+                                       "target beneath not done yet\n");
+                 return ret;
+               }
 
               if (single_step_breakpoints_inserted ())
                 remove_single_step_breakpoints ();
 
              if (record_resume_step)
-               return ret;
+               return ret;
 
              /* Is this a SIGTRAP?  */
              if (status->kind == TARGET_WAITKIND_STOPPED
-                 && status->value.sig == TARGET_SIGNAL_TRAP)
+                 && status->value.sig == GDB_SIGNAL_TRAP)
                {
                  struct regcache *regcache;
                  struct address_space *aspace;
@@ -1162,7 +1247,8 @@ record_wait (struct target_ops *ops,
                         handle it.  */
                      if (software_breakpoint_inserted_here_p (aspace, tmp_pc))
                        {
-                         struct gdbarch *gdbarch = get_regcache_arch (regcache);
+                         struct gdbarch *gdbarch
+                           = get_regcache_arch (regcache);
                          CORE_ADDR decr_pc_after_break
                            = gdbarch_decr_pc_after_break (gdbarch);
                          if (decr_pc_after_break)
@@ -1179,10 +1265,10 @@ record_wait (struct target_ops *ops,
                       int step = 1;
 
                      if (!record_message_wrapper_safe (regcache,
-                                                        TARGET_SIGNAL_0))
+                                                        GDB_SIGNAL_0))
                        {
                            status->kind = TARGET_WAITKIND_STOPPED;
-                           status->value.sig = TARGET_SIGNAL_0;
+                           status->value.sig = GDB_SIGNAL_0;
                            break;
                        }
 
@@ -1198,9 +1284,13 @@ record_wait (struct target_ops *ops,
                          set_executing (inferior_ptid, 1);
                        }
 
+                     if (record_debug)
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: record_wait "
+                                           "issuing one more step in the target beneath\n");
                      record_beneath_to_resume (record_beneath_to_resume_ops,
                                                ptid, step,
-                                               TARGET_SIGNAL_0);
+                                               GDB_SIGNAL_0);
                      continue;
                    }
                }
@@ -1333,12 +1423,13 @@ record_wait (struct target_ops *ops,
                  if (record_hw_watchpoint)
                    {
                      if (record_debug)
-                       fprintf_unfiltered (gdb_stdlog, "\
-Process record: hit hw watchpoint.\n");
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: hit hw "
+                                           "watchpoint.\n");
                      continue_flag = 0;
                    }
                  /* Check target signal */
-                 if (record_list->u.end.sigval != TARGET_SIGNAL_0)
+                 if (record_list->u.end.sigval != GDB_SIGNAL_0)
                    /* FIXME: better way to check */
                    continue_flag = 0;
                }
@@ -1362,12 +1453,12 @@ Process record: hit hw watchpoint.\n");
 
 replay_out:
       if (record_get_sig)
-       status->value.sig = TARGET_SIGNAL_INT;
-      else if (record_list->u.end.sigval != TARGET_SIGNAL_0)
+       status->value.sig = GDB_SIGNAL_INT;
+      else if (record_list->u.end.sigval != GDB_SIGNAL_0)
        /* FIXME: better way to check */
        status->value.sig = record_list->u.end.sigval;
       else
-       status->value.sig = TARGET_SIGNAL_TRAP;
+       status->value.sig = GDB_SIGNAL_TRAP;
 
       discard_cleanups (old_cleanups);
     }
@@ -1378,6 +1469,24 @@ replay_out:
   return inferior_ptid;
 }
 
+static ptid_t
+record_wait (struct target_ops *ops,
+            ptid_t ptid, struct target_waitstatus *status,
+            int options)
+{
+  ptid_t return_ptid;
+
+  return_ptid = record_wait_1 (ops, ptid, status, options);
+  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
+        core wants us resumed again.  */
+      record_resumed = 0;
+    }
+  return return_ptid;
+}
+
 static int
 record_stopped_by_watchpoint (void)
 {
@@ -1613,24 +1722,97 @@ record_xfer_partial (struct target_ops *ops, enum target_object object,
                                          offset, len);
 }
 
-/* Behavior is conditional on RECORD_IS_REPLAY.
-   We will not actually insert or remove breakpoints when replaying,
-   nor when recording.  */
+/* This structure represents a breakpoint inserted while the record
+   target is active.  We use this to know when to install/remove
+   breakpoints in/from the target beneath.  For example, a breakpoint
+   may be inserted while recording, but removed when not replaying nor
+   recording.  In that case, the breakpoint had not been inserted on
+   the target beneath, so we should not try to remove it there.  */
+
+struct record_breakpoint
+{
+  /* The address and address space the breakpoint was set at.  */
+  struct address_space *address_space;
+  CORE_ADDR addr;
+
+  /* True when the breakpoint has been also installed in the target
+     beneath.  This will be false for breakpoints set during replay or
+     when recording.  */
+  int in_target_beneath;
+};
+
+typedef struct record_breakpoint *record_breakpoint_p;
+DEF_VEC_P(record_breakpoint_p);
+
+/* The list of breakpoints inserted while the record target is
+   active.  */
+VEC(record_breakpoint_p) *record_breakpoints = NULL;
+
+static void
+record_sync_record_breakpoints (struct bp_location *loc, void *data)
+{
+  if (loc->loc_type != bp_loc_software_breakpoint)
+      return;
+
+  if (loc->inserted)
+    {
+      struct record_breakpoint *bp = XNEW (struct record_breakpoint);
+
+      bp->addr = loc->target_info.placed_address;
+      bp->address_space = loc->target_info.placed_address_space;
+
+      bp->in_target_beneath = 1;
+
+      VEC_safe_push (record_breakpoint_p, record_breakpoints, bp);
+    }
+}
+
+/* Sync existing breakpoints to record_breakpoints.  */
+
+static void
+record_init_record_breakpoints (void)
+{
+  VEC_free (record_breakpoint_p, record_breakpoints);
+
+  iterate_over_bp_locations (record_sync_record_breakpoints);
+}
+
+/* Behavior is conditional on RECORD_IS_REPLAY.  We will not actually
+   insert or remove breakpoints in the real target when replaying, nor
+   when recording.  */
 
 static int
 record_insert_breakpoint (struct gdbarch *gdbarch,
                          struct bp_target_info *bp_tgt)
 {
+  struct record_breakpoint *bp;
+  int in_target_beneath = 0;
+
   if (!RECORD_IS_REPLAY)
     {
-      struct cleanup *old_cleanups = record_gdb_operation_disable_set ();
-      int ret = record_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
-
+      /* When recording, we currently always single-step, so we don't
+        really need to install regular breakpoints in the inferior.
+        However, we do have to insert software single-step
+        breakpoints, in case the target can't hardware step.  To keep
+        things single, we always insert.  */
+      struct cleanup *old_cleanups;
+      int ret;
+
+      old_cleanups = record_gdb_operation_disable_set ();
+      ret = record_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
       do_cleanups (old_cleanups);
 
-      return ret;
+      if (ret != 0)
+       return ret;
+
+      in_target_beneath = 1;
     }
 
+  bp = XNEW (struct record_breakpoint);
+  bp->addr = bp_tgt->placed_address;
+  bp->address_space = bp_tgt->placed_address_space;
+  bp->in_target_beneath = in_target_beneath;
+  VEC_safe_push (record_breakpoint_p, record_breakpoints, bp);
   return 0;
 }
 
@@ -1640,17 +1822,35 @@ static int
 record_remove_breakpoint (struct gdbarch *gdbarch,
                          struct bp_target_info *bp_tgt)
 {
-  if (!RECORD_IS_REPLAY)
+  struct record_breakpoint *bp;
+  int ix;
+
+  for (ix = 0;
+       VEC_iterate (record_breakpoint_p, record_breakpoints, ix, bp);
+       ++ix)
     {
-      struct cleanup *old_cleanups = record_gdb_operation_disable_set ();
-      int ret = record_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
+      if (bp->addr == bp_tgt->placed_address
+         && bp->address_space == bp_tgt->placed_address_space)
+       {
+         if (bp->in_target_beneath)
+           {
+             struct cleanup *old_cleanups;
+             int ret;
 
-      do_cleanups (old_cleanups);
+             old_cleanups = record_gdb_operation_disable_set ();
+             ret = record_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
+             do_cleanups (old_cleanups);
+
+             if (ret != 0)
+               return ret;
+           }
 
-      return ret;
+         VEC_unordered_remove (record_breakpoint_p, record_breakpoints, ix);
+         return 0;
+       }
     }
 
-  return 0;
+  gdb_assert_not_reached ("removing unknown breakpoint");
 }
 
 /* "to_can_execute_reverse" method for process record target.  */
@@ -1712,6 +1912,37 @@ record_goto_bookmark (gdb_byte *bookmark, int from_tty)
   return;
 }
 
+static void
+record_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_beneath_to_async != NULL)
+    record_beneath_to_async (callback, context);
+}
+
+static int
+record_can_async_p (void)
+{
+  /* We only enable async when the user specifically asks for it.  */
+  return target_async_permitted;
+}
+
+static int
+record_is_async_p (void)
+{
+  /* We only enable async when the user specifically asks for it.  */
+  return target_async_permitted;
+}
+
+static enum exec_direction_kind
+record_execution_direction (void)
+{
+  return record_execution_dir;
+}
+
 static void
 init_record_ops (void)
 {
@@ -1739,6 +1970,10 @@ init_record_ops (void)
   /* Add bookmark target methods.  */
   record_ops.to_get_bookmark = record_get_bookmark;
   record_ops.to_goto_bookmark = record_goto_bookmark;
+  record_ops.to_async = record_async;
+  record_ops.to_can_async_p = record_can_async_p;
+  record_ops.to_is_async_p = record_is_async_p;
+  record_ops.to_execution_direction = record_execution_direction;
   record_ops.to_magic = OPS_MAGIC;
 }
 
@@ -1746,9 +1981,21 @@ init_record_ops (void)
 
 static void
 record_core_resume (struct target_ops *ops, ptid_t ptid, int step,
-                    enum target_signal signal)
+                    enum gdb_signal signal)
 {
   record_resume_step = step;
+  record_resumed = 1;
+  record_execution_dir = execution_direction;
+
+  /* We are about to start executing the inferior (or simulate it),
+     let's register it with the event loop.  */
+  if (target_can_async_p ())
+    {
+      target_async (inferior_event_handler, 0);
+
+      /* Notify the event loop there's an event to wait for.  */
+      mark_async_event_handler (record_async_inferior_event_token);
+    }
 }
 
 /* "to_kill" method for prec over corefile.  */
@@ -1916,8 +2163,8 @@ record_core_remove_breakpoint (struct gdbarch *gdbarch,
 
 /* "to_has_execution" method for prec over corefile.  */
 
-int
-record_core_has_execution (struct target_ops *ops)
+static int
+record_core_has_execution (struct target_ops *ops, ptid_t the_ptid)
 {
   return 1;
 }
@@ -1948,6 +2195,10 @@ init_record_core_ops (void)
   /* Add bookmark target methods.  */
   record_core_ops.to_get_bookmark = record_get_bookmark;
   record_core_ops.to_goto_bookmark = record_goto_bookmark;
+  record_core_ops.to_async = record_async;
+  record_core_ops.to_can_async_p = record_can_async_p;
+  record_core_ops.to_is_async_p = record_is_async_p;
+  record_core_ops.to_execution_direction = record_execution_direction;
   record_core_ops.to_magic = OPS_MAGIC;
 }
 
@@ -2029,8 +2280,8 @@ static struct cmd_list_element *record_cmdlist, *set_record_cmdlist,
 static void
 set_record_command (char *args, int from_tty)
 {
-  printf_unfiltered (_("\
-\"set record\" must be followed by an apporpriate subcommand.\n"));
+  printf_unfiltered (_("\"set record\" must be followed "
+                      "by an apporpriate subcommand.\n"));
   help_list (set_record_cmdlist, "set record ", all_commands, gdb_stdout);
 }
 
@@ -2147,7 +2398,7 @@ bfdcore_read (bfd *obfd, asection *osec, void *buf, int len, int *offset)
   if (ret)
     *offset += len;
   else
-    error (_("Failed to read %d bytes from core file %s ('%s').\n"),
+    error (_("Failed to read %d bytes from core file %s ('%s')."),
           len, bfd_get_filename (obfd),
           bfd_errmsg (bfd_get_error ()));
 }
@@ -2207,12 +2458,12 @@ record_restore (void)
 
   /* Now need to find our special note section.  */
   osec = bfd_get_section_by_name (core_bfd, "null0");
-  osec_size = bfd_section_size (core_bfd, osec);
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog, "Find precord section %s.\n",
                        osec ? "succeeded" : "failed");
   if (osec == NULL)
     return;
+  osec_size = bfd_section_size (core_bfd, osec);
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog, "%s", bfd_section_name (core_bfd, osec));
 
@@ -2222,8 +2473,9 @@ record_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_FILE_MAGIC (0x%s)\n",
+    fprintf_unfiltered (gdb_stdlog,
+                       "  Reading 4-byte magic cookie "
+                       "RECORD_FILE_MAGIC (0x%s)\n",
                        phex_nz (netorder32 (magic), 4));
 
   /* Restore the entries in recfd into record_arch_list_head and
@@ -2260,8 +2512,9 @@ record_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",
+           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);
@@ -2285,8 +2538,9 @@ record_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",
+           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),
@@ -2311,8 +2565,9 @@ record_restore (void)
          rec->u.end.insn_num = count;
          record_insn_count = count + 1;
          if (record_debug)
-           fprintf_unfiltered (gdb_stdlog, "\
-  Reading record_end (1 + %lu + %lu bytes), offset == %s\n",
+           fprintf_unfiltered (gdb_stdlog,
+                               "  Reading record_end (1 + "
+                               "%lu + %lu bytes), offset == %s\n",
                                (unsigned long) sizeof (signal),
                                (unsigned long) sizeof (count),
                                paddress (get_current_arch (),
@@ -2362,7 +2617,7 @@ bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset)
   if (ret)
     *offset += len;
   else
-    error (_("Failed to write %d bytes to core file %s ('%s').\n"),
+    error (_("Failed to write %d bytes to core file %s ('%s')."),
           len, bfd_get_filename (obfd),
           bfd_errmsg (bfd_get_error ()));
 }
@@ -2489,8 +2744,9 @@ cmd_record_save (char *args, int from_tty)
   /* Write the magic code.  */
   magic = RECORD_FILE_MAGIC;
   if (record_debug)
-    fprintf_unfiltered (gdb_stdlog, "\
-  Writing 4-byte magic cookie RECORD_FILE_MAGIC (0x%s)\n",
+    fprintf_unfiltered (gdb_stdlog,
+                       "  Writing 4-byte magic cookie "
+                       "RECORD_FILE_MAGIC (0x%s)\n",
                      phex_nz (magic, 4));
   bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset);
 
@@ -2513,8 +2769,9 @@ cmd_record_save (char *args, int from_tty)
             {
             case record_reg: /* reg */
              if (record_debug)
-               fprintf_unfiltered (gdb_stdlog, "\
-  Writing register %d (1 plus %lu plus %d bytes)\n",
+               fprintf_unfiltered (gdb_stdlog,
+                                   "  Writing register %d (1 "
+                                   "plus %lu plus %d bytes)\n",
                                    record_list->u.reg.num,
                                    (unsigned long) sizeof (regnum),
                                    record_list->u.reg.len);
@@ -2531,8 +2788,9 @@ cmd_record_save (char *args, int from_tty)
 
             case record_mem: /* mem */
              if (record_debug)
-               fprintf_unfiltered (gdb_stdlog, "\
-  Writing memory %s (1 plus %lu plus %lu plus %d bytes)\n",
+               fprintf_unfiltered (gdb_stdlog,
+                                   "  Writing memory %s (1 plus "
+                                   "%lu plus %lu plus %d bytes)\n",
                                    paddress (gdbarch,
                                              record_list->u.mem.addr),
                                    (unsigned long) sizeof (addr),
@@ -2555,8 +2813,9 @@ cmd_record_save (char *args, int from_tty)
 
               case record_end:
                if (record_debug)
-                 fprintf_unfiltered (gdb_stdlog, "\
-  Writing record_end (1 + %lu + %lu bytes)\n", 
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "  Writing record_end (1 + "
+                                     "%lu + %lu bytes)\n", 
                                      (unsigned long) sizeof (signal),
                                      (unsigned long) sizeof (count));
                /* Write signal value.  */
@@ -2603,555 +2862,6 @@ cmd_record_save (char *args, int from_tty)
                   recfilename);
 }
 
-/* For "record pic" command.  */
-
-static struct cmd_list_element *set_record_pic_cmdlist,
-                               *show_record_pic_cmdlist;
-
-static void
-set_record_pic_command (char *args, int from_tty)
-{
-  printf_unfiltered (_("\
-\"set record pic\" must be followed by an apporpriate subcommand.\n"));
-  help_list (set_record_cmdlist, "set record pic ", all_commands, gdb_stdout);
-}
-
-static void
-show_record_pic_command (char *args, int from_tty)
-{
-  cmd_show_list (show_record_pic_cmdlist, from_tty, "");
-}
-
-static const char record_pic_function[] = "function";
-static const char record_pic_line[] = "line";
-static const char *record_pic_enum[] =
-{
-  record_pic_function,
-  record_pic_line,
-  NULL,
-};
-static const char *set_record_pic_type = record_pic_line;
-
-static int record_pic_hide_nofunction = 1;
-static int record_pic_hide_nosource = 1;
-static int  record_pic_hide_same = 1;
-
-static void
-record_pic_fputs (FILE *fp, const char *buf)
-{
-  if (fputs (buf, fp) == EOF)
-    error (_("Write to file error."));
-}
-
-struct function_list
-{
-  struct function_list *next;
-  CORE_ADDR addr;
-  int fid;
-};
-struct node_list
-{
-  struct node_list *next;
-  int count;
-  CORE_ADDR addr;
-  int showall;
-  struct symtab *symtab;
-  int line;
-  struct minimal_symbol *function;
-  int fid;
-};
-struct edge_list
-{
-  struct edge_list *next;
-  int count;
-  struct node_list *s;
-  struct node_list *t;
-  int frame_diff;
-  int is_return;
-};
-struct function_list *function_list = NULL;
-struct node_list *node_list = NULL;
-struct edge_list *edge_list = NULL;
-
-static void
-record_pic_cleanups (void *data)
-{
-  FILE *fp = data;
-  struct function_list *fl, *fl2;
-  struct node_list *nl, *nl2;
-  struct edge_list *el, *el2;
-
-  fl = function_list;
-  while (fl)
-    {
-      fl2 = fl;
-      fl = fl->next;
-      xfree (fl2);
-    }
-  function_list = NULL;
-
-  nl = node_list;
-  while (nl)
-    {
-      nl2 = nl;
-      nl = nl->next;
-      xfree (nl2);
-    }
-  node_list = NULL;
-
-  el = edge_list;
-  while (el)
-    {
-      el2 = el;
-      el = el->next;
-      xfree (el2);
-    }
-  edge_list = NULL;
-
-  fclose (fp);
-}
-
-static void
-record_pic_node (char *buf, int buf_max, struct gdbarch *gdbarch,
-                 const char *type, struct node_list *nlp)
-{
-  if (type == record_pic_function)
-    {
-      snprintf (buf, buf_max, "%s %s %s",
-               (nlp->symtab) ? nlp->symtab->filename : "",
-                (nlp->function) ? SYMBOL_LINKAGE_NAME (nlp->function) : "",
-                (!nlp->function) ? paddress (gdbarch, nlp->addr) : "");
-    }
-  else
-    {
-      if (nlp->showall)
-        {
-         snprintf (buf, buf_max, "%s:%d %s %s", nlp->symtab->filename,
-                    nlp->line,
-                    (nlp->function) ? SYMBOL_LINKAGE_NAME (nlp->function) : "",
-                    paddress (gdbarch, nlp->addr));
-        }
-      else
-        {
-          if (nlp->symtab)
-           snprintf (buf, buf_max, "%s %d %s",
-                      (nlp->function) ? SYMBOL_LINKAGE_NAME (nlp->function) : "",
-                      nlp->line, paddress (gdbarch, nlp->addr));
-          else
-            snprintf (buf, buf_max, "%s %s",
-                      (nlp->function) ? SYMBOL_LINKAGE_NAME (nlp->function) : "",
-                      paddress (gdbarch, nlp->addr));
-        }
-    }
-}
-
-static void
-record_pic_edge (char *buf, int buf_max, struct edge_list *elp,
-                char *node, char *prev_node)
-{
-  if (elp->frame_diff)
-    {
-      if (elp->is_return)
-        snprintf (buf, buf_max, "edge: {color:blue sourcename: \"%s\" "
-                                "targetname: \"%s\"",
-                 prev_node, node);
-      else
-        snprintf (buf, buf_max, "edge: {color:red sourcename: \"%s\" "
-                                "targetname: \"%s\"",
-                 prev_node, node);
-    }
-  else
-    snprintf (buf, buf_max,
-              "edge: {sourcename: \"%s\" targetname: \"%s\"",
-              prev_node, node);
-}
-
-/* Save the execution log to a vcg file.  */
-
-static void
-cmd_record_pic (char *args, int from_tty)
-{
-  char *recfilename, recfilename_buffer[40];
-  FILE *fp;
-  struct cleanup *old_cleanups, *set_cleanups;
-  struct regcache *regcache;
-  struct gdbarch *gdbarch;
-  struct record_entry *cur_record_list;
-  char prev_node[256], line[256];
-  CORE_ADDR prev_addr;
-  struct frame_id fi, caller_fi, prev_fi, prev_caller_fi;
-  struct function_list *function_list_tail, *function_list_prev;
-  struct edge_list *edge_list_tail = NULL;
-  struct node_list *node_list_tail = NULL;
-  struct symtab_and_line sal, prev_sal;
-  struct node_list *prev_nlp;
-  struct node_list prev_nlp_real;
-  int fid_count = 1;
-
-  /* Check if record target is running.  */
-  if (current_target.to_stratum != record_stratum)
-    error (_("This command can only be used with target 'record' \
-or target 'record-core'."));
-
-  if (args && *args)
-    recfilename = args;
-  else
-    {
-      /* Default recfile name is "gdb_record_PID.vcg".  */
-      snprintf (recfilename_buffer, sizeof (recfilename_buffer),
-                "gdb_record_%d.vcg", PIDGET (inferior_ptid));
-      recfilename = recfilename_buffer;
-    }
-
-  /* Open the output file.  */
-  fp = fopen (recfilename, "wb");
-  if (!fp)
-    error (_("Unable to open file '%s'"), recfilename);
-
-  old_cleanups = make_cleanup (record_pic_cleanups, fp);
-
-  /* Save the current record entry to "cur_record_list".  */
-  cur_record_list = record_list;
-
-  /* Get the values of regcache and gdbarch.  */
-  regcache = get_current_regcache ();
-  gdbarch = get_regcache_arch (regcache);
-
-  /* Disable the GDB operation record.  */
-  set_cleanups = record_gdb_operation_disable_set ();
-
-  /* Reverse execute to the begin of record list.  */
-  while (1)
-    {
-      /* Check for beginning and end of log.  */
-      if (record_list == &record_first)
-        break;
-
-      record_exec_insn (regcache, gdbarch, record_list);
-
-      if (record_list->prev)
-        record_list = record_list->prev;
-    }
-
-  /* Write out the record log.  */
-  /* Write the head.  */
-  record_pic_fputs (fp, "graph: {title: \"GDB process record\"\n");
-
-  /* Write the first node.  */
-  record_pic_fputs (fp, "node: {title: \"[BEGIN]\" vertical_order:0}\n");
-
-  /* Initialization.  */
-  snprintf (prev_node, 256, "[BEGIN]");
-  prev_fi = null_frame_id;
-  prev_caller_fi = null_frame_id;
-  prev_addr = 0;
-  prev_sal.symtab = NULL;
-  prev_sal.pc = 0;
-  prev_sal.end = 0;
-  prev_nlp_real.addr = 0;
-  prev_nlp = &prev_nlp_real;
-
-  /* Create first entry for function_list.  */
-  function_list = xmalloc (sizeof (struct function_list));
-  function_list->next = NULL;
-  function_list->addr = 0;
-  function_list->fid = -1;
-  function_list_tail = function_list;
-  function_list_prev = function_list;
-
-  /* Save the entries to fp and forward execute to the end of
-     record list.  */
-  record_list = &record_first;
-  while (1)
-    {
-      if (record_list->type == record_end)
-        {
-          int frame_diff = 0;
-          CORE_ADDR addr = regcache_read_pc (regcache);
-
-          /* Check if the ADDR is stil in the same line with the
-             prev cycle.  */
-          if (prev_sal.symtab
-              && addr >= prev_sal.pc && addr < prev_sal.end)
-            goto exec;
-          sal = find_pc_line (addr, 0);
-
-          if (record_pic_hide_nosource && !sal.symtab)
-            goto exec;
-
-          /* Check if the inferior is in same frame with prev cycle.
-             Check both the current fi and caller fi because the last
-             addr of function is different with current function.  */
-          reinit_frame_cache ();
-          fi = get_frame_id (get_current_frame ());
-          caller_fi = frame_unwind_caller_id (get_current_frame ());
-          if (!frame_id_eq (prev_fi, fi)
-              && !frame_id_eq (prev_caller_fi, caller_fi))
-            frame_diff = 1;
-
-          if (set_record_pic_type == record_pic_line || frame_diff)
-            {
-              int is_return = 0;
-              struct node_list *nlp = NULL;
-              struct edge_list *elp = NULL;
-              char node[256];
-              struct minimal_symbol *function;
-
-             /* Get the node addr.  */
-              if (set_record_pic_type == record_pic_function)
-                {
-                  /* Get the start addr of function.  */
-                  addr = get_pc_function_start (addr);
-                  if (addr == 0)
-                    {
-                      if (record_pic_hide_nofunction)
-                        goto exec;
-                      addr = regcache_read_pc (regcache);
-                    }
-                }
-              else
-                {
-                  /* Get the start addr of line.  */
-                  if (sal.symtab)
-                    addr = sal.pc;
-                }
-
-              function = lookup_minimal_symbol_by_pc (addr);
-              if (!function && record_pic_hide_nofunction)
-                goto exec;
-
-              if (frame_id_eq (fi, prev_caller_fi))
-                is_return = 1;
-
-              if (record_pic_hide_same)
-                {
-                  /* Check if addr in node_list.  */
-                  for (nlp = node_list; nlp; nlp = nlp->next)
-                    {
-                      if (nlp->addr == addr)
-                        {
-                         if (!is_return
-                             || set_record_pic_type != record_pic_function)
-                            nlp->count ++;
-                          break;
-                        }
-                    }
-
-                  /* Check if prev_addr and addr in edge_list.  */
-                 if (nlp)
-                   {
-                      for (elp = edge_list; elp; elp = elp->next)
-                        {
-                          if (elp->s->addr == prev_addr && elp->t->addr == addr)
-                            {
-                              elp->count ++;
-                              break;
-                            }
-                        }
-                   }
-                }
-
-              if (!nlp)
-                {
-                  struct node_list nl;
-                  CORE_ADDR function_addr;
-                  struct function_list *flp;
-
-                  nl.addr = addr;
-                  if (frame_diff && sal.symtab)
-                    nl.showall = 1;
-                  else
-                    nl.showall = 0;
-                  nl.symtab = sal.symtab;
-                  nl.line = sal.line;
-                  nl.function = function;
-
-                  /* Get the fid of the nl.  */
-                  if (set_record_pic_type != record_pic_function)
-                    function_addr = get_pc_function_start (addr);
-                  else
-                    function_addr = addr;
-                  if (function_list_prev->addr == function_addr)
-                    nl.fid = function_list_prev->fid;
-                  else
-                    {
-                      for (flp = function_list; flp; flp = flp->next)
-                        {
-                          if (flp->addr == function_addr)
-                            {
-                              nl.fid = flp->fid;
-                              break;
-                            }
-                        }
-                      if (flp == NULL)
-                        {
-                          /* Creat a new entry to function_list.  */
-                          nl.fid = fid_count ++;
-                          flp = xmalloc (sizeof (struct function_list));
-                          flp->addr = function_addr;
-                          flp->fid = nl.fid;
-                          flp->next = NULL;
-                         function_list_tail->next = flp;
-                          function_list_tail = flp;
-                        }
-                      function_list_prev = flp;
-                    }
-
-                  if (record_pic_hide_same)
-                    {
-                      nlp = xmalloc (sizeof (struct node_list));
-                      *nlp = nl;
-                      nlp->count = 1;
-
-                      /* Add node to node_list.  */
-                      nlp->next = NULL;
-                     if (node_list_tail)
-                        node_list_tail->next = nlp;
-                     if (node_list == NULL)
-                       node_list = nlp;
-                      node_list_tail = nlp;
-                    }
-                  else
-                    {
-                      /* Draw the node.  */
-                      record_pic_node (node, 256, gdbarch,
-                                       set_record_pic_type, &nl);
-                     snprintf (line, 256, "%s i:%s", node,
-                               pulongest (record_list->u.end.insn_num));
-                     strcpy (node, line);
-                      snprintf (line, 256, "node: {title: \"%s\" "
-                                           "vertical_order: %d}\n",
-                                node, nl.fid);
-                      record_pic_fputs (fp, line);
-                    }
-                }
-
-              if (!elp)
-                {
-                  struct edge_list el;
-
-                  el.is_return = is_return;
-                  el.frame_diff = frame_diff;
-
-                  if (record_pic_hide_same)
-                    {
-                      elp = xmalloc (sizeof (struct edge_list));
-                      *elp = el;
-                     elp->s = prev_nlp;
-                      elp->t = nlp;
-                      elp->count = 1;
-
-                      /* Add edge to edge_list.  */
-                      elp->next = NULL;
-                     if (edge_list_tail)
-                        edge_list_tail->next = elp;
-                     if (edge_list == NULL)
-                       edge_list = elp;
-                      edge_list_tail = elp;
-                    }
-                  else
-                    {
-                      /* Draw the edge.  */
-                      record_pic_edge (line, 256, &el, node, prev_node);
-                      record_pic_fputs (fp, line);
-                     record_pic_fputs (fp, " }\n");
-                    }
-                }
-
-              if (record_pic_hide_same)
-                prev_nlp = nlp;
-              else
-                snprintf (prev_node, 256, "%s", node);
-              prev_addr = addr;
-            }
-
-          prev_sal = sal;
-          prev_fi = fi;
-          prev_caller_fi = caller_fi;
-        }
-
-exec:
-      /* Execute entry.  */
-      record_exec_insn (regcache, gdbarch, record_list);
-
-      if (record_list->next)
-        record_list = record_list->next;
-      else
-        break;
-    }
-
-  if (record_pic_hide_same)
-    {
-      struct node_list *nlp = NULL;
-      struct edge_list *elp = NULL;
-      char node[256];
-
-      for (nlp = node_list; nlp; nlp = nlp->next)
-        {
-          /* Draw the node.  */
-          record_pic_node (node, 256, gdbarch, set_record_pic_type, nlp);
-          snprintf (line, 256, "node: {title: \"%s c:%d\" "
-                               "vertical_order: %d}\n", node,
-                   nlp->count, nlp->fid);
-          record_pic_fputs (fp, line);
-       }
-
-      record_pic_node (node, 256, gdbarch, set_record_pic_type, edge_list->t);
-      snprintf (line, 256,
-               "edge: {color:red sourcename: \"[BEGIN]\" targetname: \"%s c:%d\"}\n",
-               node, edge_list->count);
-      record_pic_fputs (fp, line);
-      for (elp = edge_list->next; elp; elp = elp->next)
-        {
-          /* Draw the edge.  */
-         record_pic_node (prev_node, 256, gdbarch, set_record_pic_type,
-                          elp->s);
-         snprintf (line, 256, "%s c:%d", prev_node, elp->s->count);
-         strcpy (prev_node, line);
-         record_pic_node (node, 256, gdbarch, set_record_pic_type,
-                          elp->t);
-         snprintf (line, 256, "%s c:%d", node, elp->t->count);
-         strcpy (node, line);
-          record_pic_edge (line, 256, elp, node, prev_node);
-          record_pic_fputs (fp, line);
-          snprintf (line, 256, " label: \"c:%d\"}\n", elp->count);
-         record_pic_fputs (fp, line);
-        }
-    }
-
-  /* Write the last node.  */
-  snprintf (line, 256, "node: {title: \"[END]\" vertical_order: %d}\n",
-            fid_count);
-  record_pic_fputs (fp, line);
-  snprintf (line, 256,
-           "edge: {color:red sourcename: \"%s\" targetname: \"[END]\" }\n",
-           prev_node);
-  record_pic_fputs (fp, line);
-
-  /* Write the tail.  */
-  record_pic_fputs (fp, "}\n");
-
-  /* Reverse execute to cur_record_list.  */
-  while (1)
-    {
-      /* Check for beginning and end of log.  */
-      if (record_list == cur_record_list)
-        break;
-
-      record_exec_insn (regcache, gdbarch, record_list);
-
-      if (record_list->prev)
-        record_list = record_list->prev;
-    }
-
-  do_cleanups (set_cleanups);
-  do_cleanups (old_cleanups);
-
-  /* Succeeded.  */
-  printf_filtered (_("Saved file %s with execution log.\n"),
-                  recfilename);
-}
-
 /* record_goto_insn -- rewind the record log (forward or backward,
    depending on DIR) to the given entry, changing the program state
    correspondingly.  */
@@ -3247,6 +2957,9 @@ cmd_record_goto (char *arg, int from_tty)
   print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
 }
 
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_record;
+
 void
 _initialize_record (void)
 {
@@ -3317,8 +3030,8 @@ Argument is filename.  File must be created with 'record save'."),
   add_setshow_boolean_cmd ("stop-at-limit", no_class,
                           &record_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\
+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."),
@@ -3349,64 +3062,4 @@ When ON, query if PREC cannot record memory change of next instruction."),
                           NULL, NULL,
                           &set_record_cmdlist, &show_record_cmdlist);
 
-  /* For "record pic" command.  */
-  c = add_cmd ("pic", class_obscure, cmd_record_pic,
-              _("Save the execution log to a vcg file.\n\
-Argument is optional filename.\n\
-Default filename is 'gdb_record_<process_id>.vcg'."),
-              &record_cmdlist);
-  set_cmd_completer (c, filename_completer);
-  add_prefix_cmd ("pic", class_support, set_record_pic_command,
-                 _("Set record pic options"), &set_record_pic_cmdlist,
-                 "set record pic ", 0, &set_record_cmdlist);
-  add_prefix_cmd ("pic", class_support, show_record_pic_command,
-                 _("Show record pic options"), &show_record_pic_cmdlist,
-                 "show record pic ", 0, &show_record_cmdlist);
-  add_setshow_enum_cmd ("type", no_class,
-                       record_pic_enum, &set_record_pic_type, _("\
-Set the type of the nodes that record pic command saved."), _("\
-Show the type of the nodes that record pic command saved."), _("\
-When LINE, each node of vcg file that command record pic saved\n\
-will be a line of the inferior.\n\
-When FUNCTION, each node of vcg file that command record pic saved\n\
-will be a function of the inferior."),
-                       NULL, NULL,
-                       &set_record_pic_cmdlist, &show_record_pic_cmdlist);
-  add_setshow_boolean_cmd ("hide-nofunction", no_class,
-                          &record_pic_hide_nofunction, _("\
-Set whether record pic command hide the nodes that don't have the function name."), _("\
-Show whether record pic command hide the nodes that don't have the function name."), _("\
-Default is ON.\n\
-When ON, record pic command will hide the nodes that don't have\n\
-the function name.\n\
-When OFF, record pic command will show the nodes that don't have\n\
-the function name."),
-                          NULL, NULL,
-                          &set_record_pic_cmdlist, &show_record_pic_cmdlist);
-  add_setshow_boolean_cmd ("hide-nosource", no_class,
-                          &record_pic_hide_nosource, _("\
-Set whether record pic command hide the nodes that don't have the source message."), _("\
-Show whether record pic command hide the nodes that don't have the source message."), _("\
-Default is ON.\n\
-When ON, record pic command will hide the nodes that don't have\n\
-the source message.\n\
-When OFF, record pic command will show the nodes that don't have\n\
-the source message."),
-                          NULL, NULL,
-                          &set_record_pic_cmdlist, &show_record_pic_cmdlist);
-  add_setshow_boolean_cmd ("hide-sameaddr", no_class,
-                          &record_pic_hide_same, _("\
-Set whether record pic command hide the nodes that have the same address node in vcg file."), _("\
-Show whether record pic command hide the nodes that have the same address node in vcg file."), _("\
-Default is ON.\n\
-When ON, record pic command will hide the nodes that have\n\
-the same address node in vcg file.\n\
-And record pic will show the execute count number of this line\n\
-in format \"c:number\".\n\
-When OFF, record pic command will show the nodes that have\n\
-the same address node in vcg file.\n\
-And record pic show the instruction number in format \"i:number\"\n\
-that \"record goto\" support."),
-                          NULL, NULL,
-                          &set_record_pic_cmdlist, &show_record_pic_cmdlist);
 }