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]

[RFA/RFC Prec] Add process record skip 3/6 (record target)


2008-08-19  Hui Zhu  <teawater@gmail.com>

	* record.c (arch-utils.h): Include file.
	(record_skip_entry): New struct.
	(record_skip, record_skip_list): New variables.
	(record_open): Call "gdbarch_process_record_open".
	Reset record_skip.
	(record_close): Release record_skip_list.
	Remove all record skip breakpoints.
	(record_resume): Call record_beneath_to_resume directly
	if record_skip is true.
	(record_wait): Call record_beneath_to_wait directly
	if record_skip is true.
	(record_skip_entry_create): New function.
	(record_skip_breakpoint_handler): New function.
	(cmd_record_skip): New function.
	(cmd_record_skip_enable): New function.
	(cmd_record_skip_disable): New function.
	(record_skip_cmdlist): New variable.
	(_initialize_record): Add new command 'record skip',
	'record skip enable' and 'record skip disable'.
	* record.h (record_skip_entry_create): Extern.
	(record_skip_breakpoint_handler): Extern.

---
 record.c |  283 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 record.h |    6 +
 2 files changed, 277 insertions(+), 12 deletions(-)

--- a/record.c
+++ b/record.c
@@ -18,6 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

 #include "defs.h"
+#include "arch-utils.h"
 #include "gdbcmd.h"
 #include "regcache.h"
 #include "gdbthread.h"
@@ -78,6 +79,16 @@ struct record_entry
   } u;
 };

+struct record_skip_entry
+{
+  int id;
+  struct record_skip_entry *prev;
+  const char *name;
+  CORE_ADDR addr;
+  struct breakpoint *bp;
+  int (*record) (struct regcache *regcache);
+};
+
 /* This is the debug switch for process record.  */
 int record_debug = 0;

@@ -92,6 +103,10 @@ static int record_stop_at_limit = 1;
 static int record_insn_max_num = DEFAULT_RECORD_INSN_MAX_NUM;
 static int record_insn_num = 0;

+/* Skip record if true.  */
+static int record_skip = 0;
+static struct record_skip_entry *record_skip_list = NULL;
+
 /* The target_ops of process record.  */
 static struct target_ops record_ops;

@@ -498,10 +513,14 @@ record_open (char *name, int from_tty)

   push_target (&record_ops);

+  if (gdbarch_process_record_open_p (target_gdbarch))
+    gdbarch_process_record_open (target_gdbarch);
+
   /* Reset */
   record_insn_num = 0;
   record_list = &record_first;
   record_list->next = NULL;
+  record_skip = 0;
 }

 static void
@@ -511,6 +530,19 @@ record_close (int quitting)
     fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n");

   record_list_release (record_list);
+
+  /* Release record_skip_list.  */
+  if (record_skip_list)
+    {
+      struct record_skip_entry *entry;
+      for (entry = record_skip_list->prev; entry; entry = entry->prev)
+        {
+          xfree (record_skip_list);
+          record_skip_list = entry;
+        }
+      record_skip_list = NULL;
+    }
+  remove_record_skip_breakpoint (0, 1);
 }

 static int record_resume_step = 0;
@@ -526,17 +558,24 @@ record_resume (struct target_ops *ops, p

   if (!RECORD_IS_REPLAY)
     {
-      if (do_record_message (get_current_regcache ()))
-        {
-          record_resume_error = 0;
-        }
+      if (record_skip)
+        record_beneath_to_resume (record_beneath_to_resume_ops, ptid, step,
+                                  siggnal);
       else
         {
-          record_resume_error = 1;
-          return;
+          if (do_record_message (get_current_regcache ()))
+            {
+              record_resume_error = 0;
+            }
+          else
+            {
+              record_resume_error = 1;
+              return;
+            }
+          record_beneath_to_resume (record_beneath_to_resume_ops, ptid, 1,
+                                    siggnal);
         }
-      record_beneath_to_resume (record_beneath_to_resume_ops, ptid, 1,
-                                siggnal);
+
     }
 }

@@ -594,9 +633,10 @@ record_wait (struct target_ops *ops,
 	  return inferior_ptid;
 	}

-      if (record_resume_step)
+      if (record_resume_step || record_skip)
 	{
-	  /* This is a single step.  */
+ 	  /* This is a single step or record skip function is
+ 	     enable.  */
 	  return record_beneath_to_wait (record_beneath_to_wait_ops,
 					 ptid, status, 0);
 	}
@@ -1137,6 +1177,132 @@ init_record_ops (void)
   record_ops.to_magic = OPS_MAGIC;
 }

+void
+record_skip_entry_create (struct gdbarch *gdbarch, const char *name,
+                          int (*record) (struct regcache *regcache))
+{
+  struct minimal_symbol *msym;
+  struct record_skip_entry *entry;
+
+  gdb_assert (record != NULL);
+
+  /* Get msym.  */
+  msym = lookup_minimal_symbol (name, NULL, NULL);
+  if (!msym)
+    {
+        warning (_("Process record: failed to create record skip "
+                   "breakpoint for '%s'."), name);
+        return;
+    }
+
+  /* Alloc entry.  */
+  entry = xmalloc (sizeof (struct record_skip_entry));
+
+  /* Set entry->addr.  */
+  entry->addr = SYMBOL_VALUE_ADDRESS (msym);
+
+  /* Set entry->bp.  */
+  entry->bp = create_record_skip_breakpoint (gdbarch,
+                                             entry->addr,
+                                             bp_record_skip_start);
+
+  /* Set entry->name. */
+  entry->name = name;
+
+  /* Set entry->record.  */
+  entry->record = record;
+
+  /* Set entry->id and add entry to record_skip_list.  */
+  if (record_skip_list)
+    {
+      entry->id = record_skip_list->id + 1;
+      entry->prev = record_skip_list;
+    }
+  else
+    {
+      entry->id = 1;
+      entry->prev = NULL;
+    }
+  record_skip_list = entry;
+}
+
+void
+record_skip_breakpoint_handler (struct frame_info *frame, ptid_t ptid,
+                                int skip_type)
+{
+  if (RECORD_IS_REPLAY)
+    return;
+
+  gdb_assert (skip_type == bp_record_skip_start
+              || skip_type == bp_record_skip_stop);
+
+  if (skip_type == bp_record_skip_start)
+    {
+      /* Skip start.  */
+      struct regcache *regcache = get_thread_regcache (ptid);
+      struct gdbarch *gdbarch = get_regcache_arch (regcache);
+      CORE_ADDR caller_pc;
+      struct record_skip_entry *entry;
+      struct cleanup *old_cleanups = make_cleanup (record_message_cleanups, 0);
+
+      gdb_assert (record_skip == 0);
+
+      /* Get record_skip_entry.  */
+      for (entry = record_skip_list; entry; entry = entry->prev)
+        if (entry->addr == stop_pc)
+          break;
+      if (entry == NULL)
+        {
+          warning (_("Failed to find record skip entry in address %s."),
+                   paddress (gdbarch, stop_pc));
+          return;
+        }
+
+      /* Record the behavior of this function.  */
+      record_arch_list_head = NULL;
+      record_arch_list_tail = NULL;
+      record_check_insn_num (0);
+      if (entry->record (regcache))
+        {
+          warning (_("Process record: failed to record execution log."));
+          record_list_release (record_arch_list_tail);
+          return;
+        }
+      gdb_assert (record_arch_list_head != NULL);
+      record_list->next = record_arch_list_head;
+      record_arch_list_head->prev = record_list;
+      record_list = record_arch_list_tail;
+      if (record_insn_num == record_insn_max_num && record_insn_max_num)
+        record_list_release_first ();
+      else
+        record_insn_num++;
+
+      /* Insert a bp_record_skip_stop to stop the skip.  */
+      caller_pc = gdbarch_addr_bits_remove (gdbarch,
+                                            frame_unwind_caller_pc(frame));
+      create_record_skip_breakpoint (gdbarch, caller_pc, bp_record_skip_stop);
+
+      record_skip = 1;
+
+      if (record_debug)
+        fprintf_unfiltered (gdb_stdlog,
+                            _("Process record skip start in '%s'.\n"),
+                            entry->name);
+    }
+  else
+    {
+      /* Skip stop.  */
+      /* Remove this bp_record_skip_stop.  */
+      remove_record_skip_breakpoint (stop_pc, 0);
+
+      record_skip = 0;
+
+      if (record_debug)
+        fprintf_unfiltered (gdb_stdlog,
+                            _("Process record skip stop.\n"));
+    }
+}
+
 static void
 show_record_debug (struct ui_file *file, int from_tty,
 		   struct cmd_list_element *c, const char *value)
@@ -1191,6 +1357,89 @@ cmd_record_stop (char *args, int from_tt
     printf_unfiltered (_("Process record is not started.\n"));
 }

+static void
+cmd_record_skip (char *args, int from_tty)
+{
+  if (record_skip)
+    printf_unfiltered (_("Process record is skip.\n"));
+  else
+    printf_unfiltered (_("Process record is not skip.\n"));
+
+  if (record_skip_list)
+    {
+      int i;
+      struct record_skip_entry *entry;
+
+      printf_unfiltered (_("Id\tEnb\tAddress\t\tWhat\n"));
+      for (i = 1; 1; i++)
+        {
+          for (entry = record_skip_list; entry; entry = entry->prev)
+            if (entry->id == i)
+              break;
+          if (entry)
+            printf_unfiltered (_("%d\t%s\t%s\t%s\n"), entry->id,
+                               (entry->bp->enable_state == bp_enabled)
+                                 ? "y" : "n",
+                               paddress (get_current_arch (), entry->addr),
+                               entry->name);
+          else
+            break;
+        }
+    }
+  else
+    printf_unfiltered (_("No record skip.\n"));
+}
+
+static void
+cmd_record_skip_enable (char *args, int from_tty)
+{
+  struct record_skip_entry *entry;
+
+  if (args && *args)
+    {
+      int id = atoi (args);
+
+      for (entry = record_skip_list; entry; entry = entry->prev)
+        if (entry->id == id)
+          break;
+
+      if (entry)
+        enable_breakpoint (entry->bp);
+      else
+        printf_unfiltered (_("No record skip id %s.\n"), args);
+    }
+  else
+    {
+      for (entry = record_skip_list; entry; entry = entry->prev)
+        enable_breakpoint (entry->bp);
+    }
+}
+
+static void
+cmd_record_skip_disable (char *args, int from_tty)
+{
+  struct record_skip_entry *entry;
+
+  if (args && *args)
+    {
+      int id = atoi (args);
+
+      for (entry = record_skip_list; entry; entry = entry->prev)
+        if (entry->id == id)
+          break;
+
+      if (entry)
+        disable_breakpoint (entry->bp);
+      else
+        printf_unfiltered (_("No record skip id %s.\n"), args);
+    }
+  else
+    {
+      for (entry = record_skip_list; entry; entry = entry->prev)
+        disable_breakpoint (entry->bp);
+    }
+}
+
 /* Set upper limit of record log size.  */

 static void
@@ -1218,7 +1467,8 @@ show_record_insn_number (char *ignore, i
 }

 static struct cmd_list_element *record_cmdlist, *set_record_cmdlist,
-			       *show_record_cmdlist, *info_record_cmdlist;
+			       *show_record_cmdlist, *info_record_cmdlist,
+                               *record_skip_cmdlist;

 static void
 set_record_command (char *args, int from_tty)
@@ -1276,7 +1526,6 @@ _initialize_record (void)
 		  "info record ", 0, &infolist);
   add_alias_cmd ("rec", "record", class_obscure, 1, &infolist);

-
   add_cmd ("delete", class_obscure, cmd_record_delete,
 	   _("Delete the rest of execution log and start recording it anew."),
            &record_cmdlist);
@@ -1288,6 +1537,16 @@ _initialize_record (void)
            &record_cmdlist);
   add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist);

+  add_prefix_cmd ("skip", class_obscure, cmd_record_skip,
+		  _("Show the record skip status."),
+ 		  &record_skip_cmdlist, "record ", 0, &record_cmdlist);
+  add_cmd ("enable", class_obscure, cmd_record_skip_enable,
+	   _("Enable some record skip."),
+           &record_skip_cmdlist);
+  add_cmd ("disable", class_obscure, cmd_record_skip_disable,
+	   _("Disable some record skip."),
+           &record_skip_cmdlist);
+
   /* Record instructions number limit command.  */
   add_setshow_boolean_cmd ("stop-at-limit", no_class,
 			    &record_stop_at_limit, _("\
--- a/record.h
+++ b/record.h
@@ -28,5 +28,11 @@ extern int record_arch_list_add_reg (str
 extern int record_arch_list_add_mem (CORE_ADDR addr, int len);
 extern int record_arch_list_add_end (void);
 extern struct cleanup *record_gdb_operation_disable_set (void);
+extern void record_skip_entry_create (struct gdbarch *gdbarch,
+                                      const char *name,
+                                      int (*record) (struct regcache
*regcache));
+extern void record_skip_breakpoint_handler (struct frame_info *frame,
+                                            ptid_t ptid,
+                                            int skip_type);

 #endif /* _RECORD_H_ */

Attachment: 3-skip-record-target.txt
Description: Text document


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