This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch v9 13/23] record: make it build again


Complete the split of record into record.c and record-full.c

I ran the gdb.reverse suite on 64bit IA gnu/linux - no regressions.

Approved by Jan Kratochvil.

2013-03-04  Markus Metzger  <markus.t.metzger@intel.com>

	* target.h (target_ops): Add new fields to_info_record,
	to_save_record, to_delete_record, to_record_is_replaying,
	to_goto_record_begin, to_goto_record_end, to_goto_record.
	(target_info_record): New.
	(target_save_record): New.
	(target_supports_delete_record): New.
	(target_delete_record): New.
	(target_record_is_replaying): New.
	(target_goto_record_begin): New.
	(target_goto_record_end): New.
	(target_goto_record): New.
	* target.c (target_info_record): New.
	(target_save_record): New.
	(target_supports_delete_record): New.
	(target_delete_record): New.
	(target_record_is_replaying): New.
	(target_goto_record_begin): New.
	(target_goto_record_end): New.
	(target_goto_record): New.
	* record.h: Declare struct cmd_list_element.
	(record_cmdlist): New declaration.
	(set_record_cmdlist): New declaration.
	(show_record_cmdlist): New declaration.
	(info_record_cmdlist): New declaration.
	(cmd_record_goto): New declaration.
	* record.c: Remove unnecessary includes.
	Include inferior.h.
	(cmd_record_goto): Remove declaration.
	(record_cmdlist): Now extern. Initialize.
	(set_record_cmdlist): Now extern. Initialize.
	(show_record_cmdlist): Now extern. Initialize.
	(info_record_cmdlist): Now extern. Initialize.
	(find_record_target): New.
	(require_record_target): New.
	(cmd_record_start): Update.
	(cmd_record_delete): Remove target-specific code.
	Call target_delete_record.
	(cmd_record_stop): Unpush any record target.
	(set_record_insn_max_num): Move to record-full.c
	(set_record_command): Add comment.
	(show_record_command): Add comment.
	(info_record_command): Update comment.
	Remove target-specific code.
	Call the record target's to_info_record.
	(cmd_record_start): New.
	(cmd_record_goto): Now extern.
	Remove target-specific code.
	Call target_goto_begin,  target_goto_end, or target_goto.
	(_initialize_record): Move record target ops initialization to
	record-full.c.
	Change "record" command help text.
	Move "record restore", "record set", and "record show" commands to
	record-full.c.
	* Makefile.in (SFILES): Add record-full.c.
	(HFILES_NO_SRCDIR): Add record-full.h.
	(COMMON_OBS): Add record-full.o.
	* amd64-linux-tdep.c: Include record-full.h instead of record.h.
	* arm-tdep.c: Include record-full.h.
	* i386-linux-tdep.c: Include record-full.h instead of record.h.
	* i386-tdep.c: Include record-full.h.
	* infrun.c: Include record-full.h.
	* linux-record.c: Include record-full.h.
	* moxie-tdep.c: Include record-full.h.
	* record-full.c: Include record-full.h.
	Change module comment.
	(set_record_full_cmdlist): New.
	(show_record_full_cmdlist): New.
	(record_full_cmdlist): New.
	(record_goto_insn): New declaration.
	(record_save): New declaration.
	(record_check_insn_num): Change query string.
	(record_info): New.
	(record_delete): New.
	(record_is_replaying): New.
	(record_goto_entry): New.
	(record_goto_begin): New.
	(record_goto_end): New.
	(record_goto): New.
	(init_record_ops): Update.
	(init_record_core_ops): Update.
	(cmd_record_save): Rename to record_save. Remove target and arg checks.
	(cmd_record_start): New.
	(set_record_insn_max_num): Moved from record.c
	(set_record_full_command): New.
	(show_record_full_command): New.
	(_initialize_record_full): New.


---
 gdb/Makefile.in        |    5 +-
 gdb/amd64-linux-tdep.c |    2 +-
 gdb/arm-tdep.c         |    1 +
 gdb/i386-linux-tdep.c  |    2 +-
 gdb/i386-tdep.c        |    1 +
 gdb/infrun.c           |    1 +
 gdb/linux-record.c     |    1 +
 gdb/moxie-tdep.c       |    1 +
 gdb/record-full.c      |  319 +++++++++++++++++++++++++++++++++++++++++++++---
 gdb/record.c           |  288 +++++++++++++++-----------------------------
 gdb/record.h           |   11 ++
 gdb/target.c           |  129 +++++++++++++++++++
 gdb/target.h           |   44 +++++++
 13 files changed, 591 insertions(+), 214 deletions(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index e11e3d1..a36d576 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -753,7 +753,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	valarith.c valops.c valprint.c value.c varobj.c common/vec.c \
 	xml-tdesc.c xml-support.c \
 	inferior.c gdb_usleep.c \
-	record.c gcore.c \
+	record.c record-full.c gcore.c \
 	jit.c \
 	xml-syscall.c \
 	annotate.c common/signals.c copying.c dfp.c gdb.c inf-child.c \
@@ -829,6 +829,7 @@ dicos-tdep.h filesystem.h gcore.h gdb_wchar.h hppabsd-tdep.h \
 i386-darwin-tdep.h i386-nat.h linux-record.h moxie-tdep.h \
 osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
 python/python-internal.h python/python.h ravenscar-thread.h record.h \
+record-full.h \
 solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
 gnulib/import/extra/snippet/arg-nonnull.h gnulib/import/extra/snippet/c++defs.h \
 gnulib/import/extra/snippet/warn-on-use.h \
@@ -926,7 +927,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	prologue-value.o memory-map.o memrange.o \
 	xml-support.o xml-syscall.o xml-utils.o \
 	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
-	inferior.o osdata.o gdb_usleep.o record.o gcore.o \
+	inferior.o osdata.o gdb_usleep.o record.o record-full.o gcore.o \
 	gdb_vecs.o jit.o progspace.o skip.o probe.o \
 	common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
 	format.o registry.o btrace.o
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index e262c19..4f383db 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -48,7 +48,7 @@
 /* The syscall's XML filename for i386.  */
 #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
 
-#include "record.h"
+#include "record-full.h"
 #include "linux-record.h"
 
 /* Supported register note sections.  */
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index d890dcb..33b8d5d 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -56,6 +56,7 @@
 #include "vec.h"
 
 #include "record.h"
+#include "record-full.h"
 
 #include "features/arm-with-m.c"
 #include "features/arm-with-m-fpa-layout.c"
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index 15a1247..f96fc81 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -44,7 +44,7 @@
 /* The syscall's XML filename for i386.  */
 #define XML_SYSCALL_FILENAME_I386 "syscalls/i386-linux.xml"
 
-#include "record.h"
+#include "record-full.h"
 #include "linux-record.h"
 #include <stdint.h>
 
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 637c44d..a36a83d 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -52,6 +52,7 @@
 #include "i386-xstate.h"
 
 #include "record.h"
+#include "record-full.h"
 #include <stdint.h>
 
 #include "features/i386/i386.c"
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 1cf30fe..1e2addc 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -49,6 +49,7 @@
 #include "mi/mi-common.h"
 #include "event-top.h"
 #include "record.h"
+#include "record-full.h"
 #include "inline-frame.h"
 #include "jit.h"
 #include "tracepoint.h"
diff --git a/gdb/linux-record.c b/gdb/linux-record.c
index 5a9ec99..b8c7a4e 100644
--- a/gdb/linux-record.c
+++ b/gdb/linux-record.c
@@ -22,6 +22,7 @@
 #include "gdbtypes.h"
 #include "regcache.h"
 #include "record.h"
+#include "record-full.h"
 #include "linux-record.h"
 
 /* These macros are the values of the first argument of system call
diff --git a/gdb/moxie-tdep.c b/gdb/moxie-tdep.c
index 4b250f8..fc0f85c 100644
--- a/gdb/moxie-tdep.c
+++ b/gdb/moxie-tdep.c
@@ -37,6 +37,7 @@
 #include "trad-frame.h"
 #include "dis-asm.h"
 #include "record.h"
+#include "record-full.h"
 
 #include "gdb_assert.h"
 
diff --git a/gdb/record-full.c b/gdb/record-full.c
index ff22b95..1cbd724 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -28,6 +28,7 @@
 #include "gdbcore.h"
 #include "exec.h"
 #include "record.h"
+#include "record-full.h"
 #include "elf-bfd.h"
 #include "gcore.h"
 #include "event-loop.h"
@@ -37,7 +38,7 @@
 
 #include <signal.h>
 
-/* This module implements "target record", also known as "process
+/* This module implements "target record-full", also known as "process
    record and replay".  This target sits on top of a "normal" target
    (a target that "has execution"), and provides a record and replay
    functionality, including reverse debugging.
@@ -205,6 +206,13 @@ static ULONGEST record_insn_count;
 static struct target_ops record_ops;
 static struct target_ops record_core_ops;
 
+/* Command lists for "set/show record full".  */
+static struct cmd_list_element *set_record_full_cmdlist;
+static struct cmd_list_element *show_record_full_cmdlist;
+
+/* Command list for "record full".  */
+static struct cmd_list_element *record_full_cmdlist;
+
 /* 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,
@@ -234,6 +242,10 @@ 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 *);
 
+static void record_goto_insn (struct record_entry *entry,
+			      enum exec_direction_kind dir);
+static void record_save (char *recfilename);
+
 /* Alloc and free functions for record_reg, record_mem, and record_end 
    entries.  */
 
@@ -550,7 +562,7 @@ record_check_insn_num (int set_terminal)
 		target_terminal_ours ();
 	      q = yquery (_("Do you want to auto delete previous execution "
 			    "log entries when record/replay buffer becomes "
-			    "full (record stop-at-limit)?"));
+			    "full (record full stop-at-limit)?"));
 	      if (set_terminal)
 		target_terminal_inferior ();
 	      if (q)
@@ -1934,9 +1946,140 @@ record_execution_direction (void)
 }
 
 static void
+record_info (void)
+{
+  struct record_entry *p;
+
+  if (RECORD_IS_REPLAY)
+    printf_filtered (_("Replay mode:\n"));
+  else
+    printf_filtered (_("Record mode:\n"));
+
+  /* Find entry for first actual instruction in the log.  */
+  for (p = record_first.next;
+       p != NULL && p->type != record_end;
+       p = p->next)
+    ;
+
+  /* Do we have a log at all?  */
+  if (p != NULL && p->type == record_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));
+
+      /* If in replay mode, display where we are in the log.  */
+      if (RECORD_IS_REPLAY)
+	printf_filtered (_("Current instruction number is %s.\n"),
+			 pulongest (record_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_insn_count));
+
+      /* Display log count.  */
+      printf_filtered (_("Log contains %d instructions.\n"),
+		       record_insn_num);
+    }
+  else
+    printf_filtered (_("No instructions have been logged.\n"));
+
+  /* Display max log size.  */
+  printf_filtered (_("Max logged instructions is %d.\n"),
+		   record_insn_max_num);
+}
+
+/* The "to_record_delete" target method.  */
+
+static void
+record_delete (void)
+{
+  record_list_release_following (record_list);
+}
+
+/* The "to_record_is_replaying" target method.  */
+
+static int
+record_is_replaying (void)
+{
+  return RECORD_IS_REPLAY;
+}
+
+/* Go to a specific entry.  */
+
+static void
+record_goto_entry (struct record_entry *p)
+{
+  if (p == NULL)
+    error (_("Target insn not found."));
+  else if (p == record_list)
+    error (_("Already at target insn."));
+  else if (p->u.end.insn_num > record_list->u.end.insn_num)
+    {
+      printf_filtered (_("Go forward to insn number %s\n"),
+		       pulongest (p->u.end.insn_num));
+      record_goto_insn (p, EXEC_FORWARD);
+    }
+  else
+    {
+      printf_filtered (_("Go backward to insn number %s\n"),
+		       pulongest (p->u.end.insn_num));
+      record_goto_insn (p, EXEC_REVERSE);
+    }
+
+  registers_changed ();
+  reinit_frame_cache ();
+  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+}
+
+/* The "to_goto_record_begin" target method.  */
+
+static void
+record_goto_begin (void)
+{
+  struct record_entry *p = NULL;
+
+  for (p = &record_first; p != NULL; p = p->next)
+    if (p->type == record_end)
+      break;
+
+  record_goto_entry (p);
+}
+
+/* The "to_goto_record_end" target method.  */
+
+static void
+record_goto_end (void)
+{
+  struct record_entry *p = NULL;
+
+  for (p = record_list; p->next != NULL; p = p->next)
+    ;
+  for (; p!= NULL; p = p->prev)
+    if (p->type == record_end)
+      break;
+
+  record_goto_entry (p);
+}
+
+/* The "to_goto_record" target method.  */
+
+static void
+record_goto (ULONGEST target_insn)
+{
+  struct record_entry *p = NULL;
+
+  for (p = &record_first; p != NULL; p = p->next)
+    if (p->type == record_end && p->u.end.insn_num == target_insn)
+      break;
+
+  record_goto_entry (p);
+}
+
+static void
 init_record_ops (void)
 {
-  record_ops.to_shortname = "record";
+  record_ops.to_shortname = "record-full";
   record_ops.to_longname = "Process record and replay target";
   record_ops.to_doc =
     "Log program while executing and replay execution from log.";
@@ -1964,6 +2107,13 @@ init_record_ops (void)
   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_info_record = record_info;
+  record_ops.to_save_record = record_save;
+  record_ops.to_delete_record = record_delete;
+  record_ops.to_record_is_replaying = record_is_replaying;
+  record_ops.to_goto_record_begin = record_goto_begin;
+  record_ops.to_goto_record_end = record_goto_end;
+  record_ops.to_goto_record = record_goto;
   record_ops.to_magic = OPS_MAGIC;
 }
 
@@ -2189,6 +2339,12 @@ init_record_core_ops (void)
   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_info_record = record_info;
+  record_core_ops.to_delete_record = record_delete;
+  record_core_ops.to_record_is_replaying = record_is_replaying;
+  record_core_ops.to_goto_record_begin = record_goto_begin;
+  record_core_ops.to_goto_record_end = record_goto_end;
+  record_core_ops.to_goto_record = record_goto;
   record_core_ops.to_magic = OPS_MAGIC;
 }
 
@@ -2493,9 +2649,8 @@ record_save_cleanups (void *data)
    format, with an extra section for our data.  */
 
 static void
-cmd_record_save (char *args, int from_tty)
+record_save (char *recfilename)
 {
-  char *recfilename, recfilename_buffer[40];
   struct record_entry *cur_record_list;
   uint32_t magic;
   struct regcache *regcache;
@@ -2507,20 +2662,6 @@ cmd_record_save (char *args, int from_tty)
   asection *osec = NULL;
   int bfd_offset = 0;
 
-  if (strcmp (current_target.to_shortname, "record") != 0)
-    error (_("This command can only be used with target 'record'.\n"
-	     "Use 'target record' first.\n"));
-
-  if (args && *args)
-    recfilename = args;
-  else
-    {
-      /* Default recfile name is "gdb_record.PID".  */
-      snprintf (recfilename_buffer, sizeof (recfilename_buffer),
-                "gdb_record.%d", PIDGET (inferior_ptid));
-      recfilename = recfilename_buffer;
-    }
-
   /* Open the save file.  */
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog, "Saving execution log to core file '%s'\n",
@@ -2736,3 +2877,143 @@ record_goto_insn (struct record_entry *entry,
     } while (record_list != entry);
   do_cleanups (set_cleanups);
 }
+
+/* Alias for "target record-full".  */
+
+static void
+cmd_record_start (char *args, int from_tty)
+{
+  execute_command ("target record-full", from_tty);
+}
+
+static void
+set_record_insn_max_num (char *args, int from_tty, struct cmd_list_element *c)
+{
+  if (record_insn_num > record_insn_max_num && record_insn_max_num)
+    {
+      /* Count down record_insn_num while releasing records from list.  */
+      while (record_insn_num > record_insn_max_num)
+       {
+         record_list_release_first ();
+         record_insn_num--;
+       }
+    }
+}
+
+/* The "set record full" command.  */
+
+static void
+set_record_full_command (char *args, int from_tty)
+{
+  printf_unfiltered (_("\"set record full\" must be followed "
+		       "by an apporpriate subcommand.\n"));
+  help_list (set_record_full_cmdlist, "set record full ", all_commands,
+	     gdb_stdout);
+}
+
+/* The "show record full" command.  */
+
+static void
+show_record_full_command (char *args, int from_tty)
+{
+  cmd_show_list (show_record_full_cmdlist, from_tty, "");
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_record_full;
+
+void
+_initialize_record_full (void)
+{
+  struct cmd_list_element *c;
+
+  /* Init record_first.  */
+  record_first.prev = NULL;
+  record_first.next = NULL;
+  record_first.type = record_end;
+
+  init_record_ops ();
+  add_target (&record_ops);
+  add_deprecated_target_alias (&record_ops, "record");
+  init_record_core_ops ();
+  add_target (&record_core_ops);
+
+  add_prefix_cmd ("full", class_obscure, cmd_record_start,
+		  _("Start full execution recording."), &record_full_cmdlist,
+		  "record full ", 0, &record_cmdlist);
+
+  c = add_cmd ("restore", class_obscure, cmd_record_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);
+
+  /* Deprecate the old version without "full" prefix.  */
+  c = add_alias_cmd ("restore", "full restore", class_obscure, 1,
+		     &record_cmdlist);
+  set_cmd_completer (c, filename_completer);
+  deprecate_cmd (c, "record full restore");
+
+  add_prefix_cmd ("full", class_support, set_record_full_command,
+		  _("Set record options"), &set_record_full_cmdlist,
+		  "set record full ", 0, &set_record_cmdlist);
+
+  add_prefix_cmd ("full", class_support, show_record_full_command,
+		  _("Show record options"), &show_record_full_cmdlist,
+		  "show record full ", 0, &show_record_cmdlist);
+
+  /* Record instructions number limit command.  */
+  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\
+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);
+
+  c = add_alias_cmd ("stop-at-limit", "full stop-at-limit", 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,
+		     &show_record_cmdlist);
+  deprecate_cmd (c, "show record full stop-at-limit");
+
+  add_setshow_uinteger_cmd ("insn-number-max", no_class, &record_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.  Zero means unlimited.  Default is 200000."),
+			    set_record_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);
+  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);
+  deprecate_cmd (c, "show record full insn-number-max");
+
+  add_setshow_boolean_cmd ("memory-query", no_class, &record_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);
+
+  c = add_alias_cmd ("memory-query", "full memory-query", 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);
+  deprecate_cmd (c, "show record full memory-query");
+}
diff --git a/gdb/record.c b/gdb/record.c
index c06bcae..8b44717 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -19,29 +19,48 @@
 
 #include "defs.h"
 #include "gdbcmd.h"
-#include "regcache.h"
-#include "gdbthread.h"
-#include "event-top.h"
-#include "exceptions.h"
 #include "completer.h"
-#include "arch-utils.h"
-#include "gdbcore.h"
-#include "exec.h"
 #include "record.h"
-#include "elf-bfd.h"
-#include "gcore.h"
-#include "event-loop.h"
-#include "inf-loop.h"
-#include "gdb_bfd.h"
 #include "observer.h"
-
-#include <signal.h>
+#include "inferior.h"
+#include "common/common-utils.h"
 
 /* This is the debug switch for process record.  */
 unsigned int record_debug = 0;
 
-/* The implementation of the command "record goto".  */
-static void cmd_record_goto (char *, int);
+struct cmd_list_element *record_cmdlist = NULL;
+struct cmd_list_element *set_record_cmdlist = NULL;
+struct cmd_list_element *show_record_cmdlist = NULL;
+struct cmd_list_element *info_record_cmdlist = NULL;
+
+/* Find the record target in the target stack.  */
+
+static struct target_ops *
+find_record_target (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_stratum == record_stratum)
+      return t;
+
+  return NULL;
+}
+
+/* Check that recording is active.  Throw an error, if it isn't.  */
+
+static struct target_ops *
+require_record_target (void)
+{
+  struct target_ops *t;
+
+  t = find_record_target ();
+  if (t == NULL)
+    error (_("No record target is currently active.\n"
+	     "Use one of the \"target record-<tab><tab>\" commands first."));
+
+  return t;
+}
 
 /* See record.h.  */
 
@@ -74,7 +93,7 @@ show_record_debug (struct ui_file *file, int from_tty,
 static void
 cmd_record_start (char *args, int from_tty)
 {
-  execute_command ("target record", from_tty);
+  execute_command ("target record-full", from_tty);
 }
 
 /* Truncate the record log from the present point
@@ -83,21 +102,25 @@ cmd_record_start (char *args, int from_tty)
 static void
 cmd_record_delete (char *args, int from_tty)
 {
-  if (current_target.to_stratum == record_stratum)
+  require_record_target ();
+
+  if (!target_record_is_replaying ())
     {
-      if (RECORD_IS_REPLAY)
-	{
-	  if (!from_tty || query (_("Delete the log from this point forward "
-		                    "and begin to record the running message "
-		                    "at current PC?")))
-	    record_list_release_following (record_list);
-	}
-      else
-	  printf_unfiltered (_("Already at end of record list.\n"));
+      printf_unfiltered (_("Already at end of record list.\n"));
+      return;
+    }
 
+  if (!target_supports_delete_record ())
+    {
+      printf_unfiltered (_("The current record target does not support "
+			   "this operation.\n"));
+      return;
     }
-  else
-    printf_unfiltered (_("Process record is not started.\n"));
+
+  if (!from_tty || query (_("Delete the log from this point forward "
+			    "and begin to record the running message "
+			    "at current PC?")))
+    target_delete_record ();
 }
 
 /* Implement the "stoprecord" or "record stop" command.  */
@@ -105,36 +128,18 @@ cmd_record_delete (char *args, int from_tty)
 static void
 cmd_record_stop (char *args, int from_tty)
 {
-  if (current_target.to_stratum == record_stratum)
-    {
-      unpush_target (&record_ops);
-      printf_unfiltered (_("Process record is stopped and all execution "
-                           "logs are deleted.\n"));
+  struct target_ops *t;
 
-      observer_notify_record_changed (current_inferior (), 0);
-    }
-  else
-    printf_unfiltered (_("Process record is not started.\n"));
-}
+  t = require_record_target ();
+  unpush_target (t);
 
-/* Set upper limit of record log size.  */
+  printf_unfiltered (_("Process record is stopped and all execution "
+		       "logs are deleted.\n"));
 
-static void
-set_record_insn_max_num (char *args, int from_tty, struct cmd_list_element *c)
-{
-  if (record_insn_num > record_insn_max_num && record_insn_max_num)
-    {
-      /* Count down record_insn_num while releasing records from list.  */
-      while (record_insn_num > record_insn_max_num)
-	{
-	  record_list_release_first ();
-	  record_insn_num--;
-	}
-    }
+  observer_notify_record_changed (current_inferior (), 0);
 }
 
-static struct cmd_list_element *record_cmdlist, *set_record_cmdlist,
-			       *show_record_cmdlist, *info_record_cmdlist;
+/* The "set record" command.  */
 
 static void
 set_record_command (char *args, int from_tty)
@@ -144,65 +149,53 @@ set_record_command (char *args, int from_tty)
   help_list (set_record_cmdlist, "set record ", all_commands, gdb_stdout);
 }
 
+/* The "show record" command.  */
+
 static void
 show_record_command (char *args, int from_tty)
 {
   cmd_show_list (show_record_cmdlist, from_tty, "");
 }
 
-/* Display some statistics about the execution log.  */
+/* The "info record" command.  */
 
 static void
 info_record_command (char *args, int from_tty)
 {
-  struct record_entry *p;
+  struct target_ops *t;
 
-  if (current_target.to_stratum == record_stratum)
+  t = find_record_target ();
+  if (t == NULL)
     {
-      if (RECORD_IS_REPLAY)
-	printf_filtered (_("Replay mode:\n"));
-      else
-	printf_filtered (_("Record mode:\n"));
-
-      /* Find entry for first actual instruction in the log.  */
-      for (p = record_first.next;
-	   p != NULL && p->type != record_end;
-	   p = p->next)
-	;
-
-      /* Do we have a log at all?  */
-      if (p != NULL && p->type == record_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));
-
-	  /* If in replay mode, display where we are in the log.  */
-	  if (RECORD_IS_REPLAY)
-	    printf_filtered (_("Current instruction number is %s.\n"),
-			     pulongest (record_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_insn_count));
-
-	  /* Display log count.  */
-	  printf_filtered (_("Log contains %d instructions.\n"), 
-			   record_insn_num);
-	}
-      else
-	{
-	  printf_filtered (_("No instructions have been logged.\n"));
-	}
+      printf_filtered (_("No record target is currently active.\n"));
+      return;
     }
+
+  printf_filtered (_("Active record target: %s\n"), t->to_shortname);
+  if (t->to_info_record != NULL)
+    t->to_info_record ();
+}
+
+/* The "record save" command.  */
+
+static void
+cmd_record_save (char *args, int from_tty)
+{
+  char *recfilename, recfilename_buffer[40];
+
+  require_record_target ();
+
+  if (args != NULL && *args != 0)
+    recfilename = args;
   else
     {
-      printf_filtered (_("target record is not active.\n"));
+      /* Default recfile name is "gdb_record.PID".  */
+      xsnprintf (recfilename_buffer, sizeof (recfilename_buffer),
+                "gdb_record.%d", PIDGET (inferior_ptid));
+      recfilename = recfilename_buffer;
     }
 
-  /* Display max log size.  */
-  printf_filtered (_("Max logged instructions is %d.\n"),
-		   record_insn_max_num);
+  target_save_record (recfilename);
 }
 
 /* "record goto" command.  Argument is an instruction number,
@@ -210,65 +203,26 @@ info_record_command (char *args, int from_tty)
 
    Rewinds the recording (forward or backward) to the given instruction.  */
 
-static void
+void
 cmd_record_goto (char *arg, int from_tty)
 {
-  struct record_entry *p = NULL;
-  ULONGEST target_insn = 0;
+  require_record_target ();
 
   if (arg == NULL || *arg == '\0')
     error (_("Command requires an argument (insn number to go to)."));
 
   if (strncmp (arg, "start", strlen ("start")) == 0
       || strncmp (arg, "begin", strlen ("begin")) == 0)
-    {
-      /* Special case.  Find first insn.  */
-      for (p = &record_first; p != NULL; p = p->next)
-	if (p->type == record_end)
-	  break;
-      if (p)
-	target_insn = p->u.end.insn_num;
-    }
+    target_goto_record_begin ();
   else if (strncmp (arg, "end", strlen ("end")) == 0)
-    {
-      /* Special case.  Find last insn.  */
-      for (p = record_list; p->next != NULL; p = p->next)
-	;
-      for (; p!= NULL; p = p->prev)
-	if (p->type == record_end)
-	  break;
-      if (p)
-	target_insn = p->u.end.insn_num;
-    }
+    target_goto_record_end ();
   else
     {
-      /* General case.  Find designated insn.  */
-      target_insn = parse_and_eval_long (arg);
+      ULONGEST insn;
 
-      for (p = &record_first; p != NULL; p = p->next)
-	if (p->type == record_end && p->u.end.insn_num == target_insn)
-	  break;
+      insn = parse_and_eval_long (arg);
+      target_goto_record (insn);
     }
-
-  if (p == NULL)
-    error (_("Target insn '%s' not found."), arg);
-  else if (p == record_list)
-    error (_("Already at insn '%s'."), arg);
-  else if (p->u.end.insn_num > record_list->u.end.insn_num)
-    {
-      printf_filtered (_("Go forward to insn number %s\n"),
-		       pulongest (target_insn));
-      record_goto_insn (p, EXEC_FORWARD);
-    }
-  else
-    {
-      printf_filtered (_("Go backward to insn number %s\n"),
-		       pulongest (target_insn));
-      record_goto_insn (p, EXEC_REVERSE);
-    }
-  registers_changed ();
-  reinit_frame_cache ();
-  print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
@@ -279,16 +233,6 @@ _initialize_record (void)
 {
   struct cmd_list_element *c;
 
-  /* Init record_first.  */
-  record_first.prev = NULL;
-  record_first.next = NULL;
-  record_first.type = record_end;
-
-  init_record_ops ();
-  add_target (&record_ops);
-  init_record_core_ops ();
-  add_target (&record_core_ops);
-
   add_setshow_zuinteger_cmd ("record", no_class, &record_debug,
 			     _("Set debugging of record/replay feature."),
 			     _("Show debugging of record/replay feature."),
@@ -298,7 +242,7 @@ _initialize_record (void)
 			     &showdebuglist);
 
   c = add_prefix_cmd ("record", class_obscure, cmd_record_start,
-		      _("Abbreviated form of \"target record\" command."),
+		      _("Start recording."),
 		      &record_cmdlist, "record ", 0, &cmdlist);
   set_cmd_completer (c, filename_completer);
 
@@ -323,12 +267,6 @@ Default filename is 'gdb_record.<process_id>'."),
 	       &record_cmdlist);
   set_cmd_completer (c, filename_completer);
 
-  c = add_cmd ("restore", class_obscure, cmd_record_restore,
-	       _("Restore the execution log from a file.\n\
-Argument is filename.  File must be created with 'record save'."),
-	       &record_cmdlist);
-  set_cmd_completer (c, filename_completer);
-
   add_cmd ("delete", class_obscure, cmd_record_delete,
 	   _("Delete the rest of execution log and start recording it anew."),
            &record_cmdlist);
@@ -340,40 +278,8 @@ Argument is filename.  File must be created with 'record save'."),
            &record_cmdlist);
   add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist);
 
-  /* Record instructions number limit command.  */
-  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\
-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_cmdlist, &show_record_cmdlist);
-  add_setshow_uinteger_cmd ("insn-number-max", no_class,
-			    &record_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.  Zero means unlimited.  Default is 200000."),
-			    set_record_insn_max_num,
-			    NULL, &set_record_cmdlist, &show_record_cmdlist);
-
   add_cmd ("goto", class_obscure, cmd_record_goto, _("\
 Restore the program to its state at instruction number N.\n\
 Argument is instruction number, as shown by 'info record'."),
 	   &record_cmdlist);
-
-  add_setshow_boolean_cmd ("memory-query", no_class,
-			   &record_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_cmdlist, &show_record_cmdlist);
-
 }
diff --git a/gdb/record.h b/gdb/record.h
index 88e59e2..b428eaf 100644
--- a/gdb/record.h
+++ b/gdb/record.h
@@ -20,14 +20,25 @@
 #ifndef _RECORD_H_
 #define _RECORD_H_
 
+struct cmd_list_element;
+
 #define RECORD_IS_USED	(current_target.to_stratum == record_stratum)
 
 extern unsigned int record_debug;
 
+/* Allow record targets to add their own sub-commands.  */
+extern struct cmd_list_element *record_cmdlist;
+extern struct cmd_list_element *set_record_cmdlist;
+extern struct cmd_list_element *show_record_cmdlist;
+extern struct cmd_list_element *info_record_cmdlist;
+
 /* Wrapper for target_read_memory that prints a debug message if
    reading memory fails.  */
 extern int record_read_memory (struct gdbarch *gdbarch,
 			       CORE_ADDR memaddr, gdb_byte *myaddr,
 			       ssize_t len);
 
+/* The "record goto" command.  */
+extern void cmd_record_goto (char *arg, int from_tty);
+
 #endif /* _RECORD_H_ */
diff --git a/gdb/target.c b/gdb/target.c
index 1771d3a..8512ae5 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4230,6 +4230,135 @@ target_read_btrace (struct btrace_target_info *btinfo)
   return NULL;
 }
 
+/* See target.h.  */
+
+void
+target_info_record (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_info_record != NULL)
+      {
+	t->to_info_record ();
+	return;
+      }
+
+  tcomplain ();
+}
+
+/* See target.h.  */
+
+void
+target_save_record (char *filename)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_save_record != NULL)
+      {
+	t->to_save_record (filename);
+	return;
+      }
+
+  tcomplain ();
+}
+
+/* See target.h.  */
+
+int
+target_supports_delete_record (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_delete_record != NULL)
+      return 1;
+
+  return 0;
+}
+
+/* See target.h.  */
+
+void
+target_delete_record (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_delete_record != NULL)
+      {
+	t->to_delete_record ();
+	return;
+      }
+
+  tcomplain ();
+}
+
+/* See target.h.  */
+
+int
+target_record_is_replaying (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_record_is_replaying != NULL)
+	return t->to_record_is_replaying ();
+
+  return 0;
+}
+
+/* See target.h.  */
+
+void
+target_goto_record_begin (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_goto_record_begin != NULL)
+      {
+	t->to_goto_record_begin ();
+	return;
+      }
+
+  tcomplain ();
+}
+
+/* See target.h.  */
+
+void
+target_goto_record_end (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_goto_record_end != NULL)
+      {
+	t->to_goto_record_end ();
+	return;
+      }
+
+  tcomplain ();
+}
+
+/* See target.h.  */
+
+void
+target_goto_record (ULONGEST insn)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_goto_record != NULL)
+      {
+	t->to_goto_record (insn);
+	return;
+      }
+
+  tcomplain ();
+}
 
 static void
 debug_to_prepare_to_store (struct regcache *regcache)
diff --git a/gdb/target.h b/gdb/target.h
index 1d73336..d416193 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -876,6 +876,27 @@ struct target_ops
     /* Read branch trace data.  */
     VEC (btrace_block_s) *(*to_read_btrace) (struct btrace_target_info *);
 
+    /* Print information about the recording.  */
+    void (*to_info_record) (void);
+
+    /* Save the recorded execution trace into a file.  */
+    void (*to_save_record) (char *filename);
+
+    /* Delete the recorded execution trace from the current position onwards.  */
+    void (*to_delete_record) (void);
+
+    /* Query if the record target is currently replaying.  */
+    int (*to_record_is_replaying) (void);
+
+    /* Go to the begin of the execution trace.  */
+    void (*to_goto_record_begin) (void);
+
+    /* Go to the end of the execution trace.  */
+    void (*to_goto_record_end) (void);
+
+    /* Go to a specific location in the recorded execution trace.  */
+    void (*to_goto_record) (ULONGEST insn);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1938,5 +1959,28 @@ extern int target_btrace_has_changed (struct btrace_target_info *btinfo);
    Returns a vector of branch trace blocks with the latest entry at index 0.  */
 extern VEC (btrace_block_s) *target_read_btrace (struct btrace_target_info *);
 
+/* See to_info_record in struct target_ops.  */
+extern void target_info_record (void);
+
+/* See to_save_record in struct target_ops.  */
+extern void target_save_record (char *filename);
+
+/* Query if the target supports deleting the execution log.  */
+extern int target_supports_delete_record (void);
+
+/* See to_delete_record in struct target_ops.  */
+extern void target_delete_record (void);
+
+/* See to_record_is_replaying in struct target_ops.  */
+extern int target_record_is_replaying (void);
+
+/* See to_goto_record_begin in struct target_ops.  */
+extern void target_goto_record_begin (void);
+
+/* See to_goto_record_end in struct target_ops.  */
+extern void target_goto_record_end (void);
+
+/* See to_goto_record in struct target_ops.  */
+extern void target_goto_record (ULONGEST insn);
 
 #endif /* !defined (TARGET_H) */
-- 
1.7.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]