Remove duplicate comment
[deliverable/binutils-gdb.git] / gdb / reverse.c
index a37d1e3a1c0ccbf27951c7e450d4367cec294c1d..541355f976ed86dce68dc8c9e7598e2f18d94832 100644 (file)
@@ -1,12 +1,12 @@
 /* Reverse execution and reverse debugging.
 
-   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2006-2014 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "gdb_string.h"
 #include "target.h"
 #include "top.h"
 #include "cli/cli-cmds.h"
 #include "cli/cli-decode.h"
+#include "cli/cli-utils.h"
 #include "inferior.h"
+#include "infrun.h"
+#include "regcache.h"
 
 /* User interface:
    reverse-step, reverse-next etc.  */
@@ -49,9 +49,6 @@ exec_reverse_once (char *cmd, char *args, int from_tty)
   enum exec_direction_kind dir = execution_direction;
   struct cleanup *old_chain;
 
-  if (dir == EXEC_ERROR)
-    error (_("Target %s does not support this command."), target_shortname);
-
   if (dir == EXEC_REVERSE)
     error (_("Already in reverse mode.  Use '%s' or 'set exec-dir forward'."),
           cmd);
@@ -103,6 +100,252 @@ reverse_finish (char *args, int from_tty)
   exec_reverse_once ("finish", args, from_tty);
 }
 
+/* Data structures for a bookmark list.  */
+
+struct bookmark {
+  struct bookmark *next;
+  int number;
+  CORE_ADDR pc;
+  struct symtab_and_line sal;
+  gdb_byte *opaque_data;
+};
+
+static struct bookmark *bookmark_chain;
+static int bookmark_count;
+
+#define ALL_BOOKMARKS(B) for ((B) = bookmark_chain; (B); (B) = (B)->next)
+
+#define ALL_BOOKMARKS_SAFE(B,TMP)           \
+     for ((B) = bookmark_chain;             \
+          (B) ? ((TMP) = (B)->next, 1) : 0; \
+          (B) = (TMP))
+
+/* save_bookmark_command -- implement "bookmark" command.
+   Call target method to get a bookmark identifier.
+   Insert bookmark identifier into list.
+
+   Identifier will be a malloc string (gdb_byte *).
+   Up to us to free it as required.  */
+
+static void
+save_bookmark_command (char *args, int from_tty)
+{
+  /* Get target's idea of a bookmark.  */
+  gdb_byte *bookmark_id = target_get_bookmark (args, from_tty);
+  struct bookmark *b, *b1;
+  struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
+
+  /* CR should not cause another identical bookmark.  */
+  dont_repeat ();
+
+  if (bookmark_id == NULL)
+    error (_("target_get_bookmark failed."));
+
+  /* Set up a bookmark struct.  */
+  b = xcalloc (1, sizeof (struct bookmark));
+  b->number = ++bookmark_count;
+  init_sal (&b->sal);
+  b->pc = regcache_read_pc (get_current_regcache ());
+  b->sal = find_pc_line (b->pc, 0);
+  b->sal.pspace = get_frame_program_space (get_current_frame ());
+  b->opaque_data = bookmark_id;
+  b->next = NULL;
+
+  /* Add this bookmark to the end of the chain, so that a list
+     of bookmarks will come out in order of increasing numbers.  */
+
+  b1 = bookmark_chain;
+  if (b1 == 0)
+    bookmark_chain = b;
+  else
+    {
+      while (b1->next)
+       b1 = b1->next;
+      b1->next = b;
+    }
+  printf_filtered (_("Saved bookmark %d at %s\n"), b->number,
+                    paddress (gdbarch, b->sal.pc));
+}
+
+/* Implement "delete bookmark" command.  */
+
+static int
+delete_one_bookmark (int num)
+{
+  struct bookmark *b1, *b;
+
+  /* Find bookmark with corresponding number.  */
+  ALL_BOOKMARKS (b)
+    if (b->number == num)
+      break;
+
+  /* Special case, first item in list.  */
+  if (b == bookmark_chain)
+    bookmark_chain = b->next;
+
+  /* Find bookmark preceding "marked" one, so we can unlink.  */
+  if (b)
+    {
+      ALL_BOOKMARKS (b1)
+       if (b1->next == b)
+         {
+           /* Found designated bookmark.  Unlink and delete.  */
+           b1->next = b->next;
+           break;
+         }
+      xfree (b->opaque_data);
+      xfree (b);
+      return 1;                /* success */
+    }
+  return 0;            /* failure */
+}
+
+static void
+delete_all_bookmarks (void)
+{
+  struct bookmark *b, *b1;
+
+  ALL_BOOKMARKS_SAFE (b, b1)
+    {
+      xfree (b->opaque_data);
+      xfree (b);
+    }
+  bookmark_chain = NULL;
+}
+
+static void
+delete_bookmark_command (char *args, int from_tty)
+{
+  int num;
+  struct get_number_or_range_state state;
+
+  if (bookmark_chain == NULL)
+    {
+      warning (_("No bookmarks."));
+      return;
+    }
+
+  if (args == NULL || args[0] == '\0')
+    {
+      if (from_tty && !query (_("Delete all bookmarks? ")))
+       return;
+      delete_all_bookmarks ();
+      return;
+    }
+
+  init_number_or_range (&state, args);
+  while (!state.finished)
+    {
+      num = get_number_or_range (&state);
+      if (!delete_one_bookmark (num))
+       /* Not found.  */
+       warning (_("No bookmark #%d."), num);
+    }
+}
+
+/* Implement "goto-bookmark" command.  */
+
+static void
+goto_bookmark_command (char *args, int from_tty)
+{
+  struct bookmark *b;
+  unsigned long num;
+  char *p = args;
+
+  if (args == NULL || args[0] == '\0')
+    error (_("Command requires an argument."));
+
+  if (strncmp (args, "start", strlen ("start")) == 0
+      || strncmp (args, "begin", strlen ("begin")) == 0
+      || strncmp (args, "end",   strlen ("end")) == 0)
+    {
+      /* Special case.  Give target opportunity to handle.  */
+      target_goto_bookmark ((gdb_byte *) args, from_tty);
+      return;
+    }
+
+  if (args[0] == '\'' || args[0] == '\"')
+    {
+      /* Special case -- quoted string.  Pass on to target.  */
+      if (args[strlen (args) - 1] != args[0])
+       error (_("Unbalanced quotes: %s"), args);
+      target_goto_bookmark ((gdb_byte *) args, from_tty);
+      return;
+    }
+
+  /* General case.  Bookmark identified by bookmark number.  */
+  num = get_number (&args);
+
+  if (num == 0)
+    error (_("goto-bookmark: invalid bookmark number '%s'."), p);
+
+  ALL_BOOKMARKS (b)
+    if (b->number == num)
+      break;
+
+  if (b)
+    {
+      /* Found.  Send to target method.  */
+      target_goto_bookmark (b->opaque_data, from_tty);
+      return;
+    }
+  /* Not found.  */
+  error (_("goto-bookmark: no bookmark found for '%s'."), p);
+}
+
+static int
+bookmark_1 (int bnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
+  struct bookmark *b;
+  int matched = 0;
+
+  ALL_BOOKMARKS (b)
+  {
+    if (bnum == -1 || bnum == b->number)
+      {
+       printf_filtered ("   %d       %s    '%s'\n",
+                        b->number,
+                        paddress (gdbarch, b->pc),
+                        b->opaque_data);
+       matched++;
+      }
+  }
+
+  if (bnum > 0 && matched == 0)
+    printf_filtered ("No bookmark #%d\n", bnum);
+
+  return matched;
+}
+
+/* Implement "info bookmarks" command.  */
+
+static void
+bookmarks_info (char *args, int from_tty)
+{
+  int bnum = -1;
+
+  if (!bookmark_chain)
+    printf_filtered (_("No bookmarks.\n"));
+  else if (args == NULL || *args == '\0')
+    bookmark_1 (-1);
+  else
+    {
+      struct get_number_or_range_state state;
+
+      init_number_or_range (&state, args);
+      while (!state.finished)
+       {
+         bnum = get_number_or_range (&state);
+         bookmark_1 (bnum);
+       }
+    }
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_reverse;
+
 void
 _initialize_reverse (void)
 {
@@ -141,4 +384,25 @@ the breakpoint won't break until the Nth time it is reached)."));
 
   add_com ("reverse-finish", class_run, reverse_finish, _("\
 Execute backward until just before selected stack frame is called."));
+
+  add_com ("bookmark", class_bookmark, save_bookmark_command, _("\
+Set a bookmark in the program's execution history.\n\
+A bookmark represents a point in the execution history \n\
+that can be returned to at a later point in the debug session."));
+  add_info ("bookmarks", bookmarks_info, _("\
+Status of user-settable bookmarks.\n\
+Bookmarks are user-settable markers representing a point in the \n\
+execution history that can be returned to later in the same debug \n\
+session."));
+  add_cmd ("bookmark", class_bookmark, delete_bookmark_command, _("\
+Delete a bookmark from the bookmark list.\n\
+Argument is a bookmark number or numbers,\n\
+ or no argument to delete all bookmarks.\n"),
+          &deletelist);
+  add_com ("goto-bookmark", class_bookmark, goto_bookmark_command, _("\
+Go to an earlier-bookmarked point in the program's execution history.\n\
+Argument is the bookmark number of a bookmark saved earlier by using \n\
+the 'bookmark' command, or the special arguments:\n\
+  start (beginning of recording)\n\
+  end   (end of recording)\n"));
 }
This page took 0.027193 seconds and 4 git commands to generate.