gdb/reverse.c - gdb

Global variables defined

Data types defined

Functions defined

Macros defined

Source code

  1. /* Reverse execution and reverse debugging.

  2.    Copyright (C) 2006-2015 Free Software Foundation, Inc.

  3.    This file is part of GDB.

  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 3 of the License, or
  7.    (at your option) any later version.

  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.

  12.    You should have received a copy of the GNU General Public License
  13.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  14. #include "defs.h"
  15. #include "target.h"
  16. #include "top.h"
  17. #include "cli/cli-cmds.h"
  18. #include "cli/cli-decode.h"
  19. #include "cli/cli-utils.h"
  20. #include "inferior.h"
  21. #include "infrun.h"
  22. #include "regcache.h"

  23. /* User interface:
  24.    reverse-step, reverse-next etc.  */

  25. static void
  26. exec_direction_default (void *notused)
  27. {
  28.   /* Return execution direction to default state.  */
  29.   execution_direction = EXEC_FORWARD;
  30. }

  31. /* exec_reverse_once -- accepts an arbitrary gdb command (string),
  32.    and executes it with exec-direction set to 'reverse'.

  33.    Used to implement reverse-next etc. commands.  */

  34. static void
  35. exec_reverse_once (char *cmd, char *args, int from_tty)
  36. {
  37.   char *reverse_command;
  38.   enum exec_direction_kind dir = execution_direction;
  39.   struct cleanup *old_chain;

  40.   if (dir == EXEC_REVERSE)
  41.     error (_("Already in reverse mode.  Use '%s' or 'set exec-dir forward'."),
  42.            cmd);

  43.   if (!target_can_execute_reverse)
  44.     error (_("Target %s does not support this command."), target_shortname);

  45.   reverse_command = xstrprintf ("%s %s", cmd, args ? args : "");
  46.   old_chain = make_cleanup (exec_direction_default, NULL);
  47.   make_cleanup (xfree, reverse_command);
  48.   execution_direction = EXEC_REVERSE;
  49.   execute_command (reverse_command, from_tty);
  50.   do_cleanups (old_chain);
  51. }

  52. static void
  53. reverse_step (char *args, int from_tty)
  54. {
  55.   exec_reverse_once ("step", args, from_tty);
  56. }

  57. static void
  58. reverse_stepi (char *args, int from_tty)
  59. {
  60.   exec_reverse_once ("stepi", args, from_tty);
  61. }

  62. static void
  63. reverse_next (char *args, int from_tty)
  64. {
  65.   exec_reverse_once ("next", args, from_tty);
  66. }

  67. static void
  68. reverse_nexti (char *args, int from_tty)
  69. {
  70.   exec_reverse_once ("nexti", args, from_tty);
  71. }

  72. static void
  73. reverse_continue (char *args, int from_tty)
  74. {
  75.   exec_reverse_once ("continue", args, from_tty);
  76. }

  77. static void
  78. reverse_finish (char *args, int from_tty)
  79. {
  80.   exec_reverse_once ("finish", args, from_tty);
  81. }

  82. /* Data structures for a bookmark list.  */

  83. struct bookmark {
  84.   struct bookmark *next;
  85.   int number;
  86.   CORE_ADDR pc;
  87.   struct symtab_and_line sal;
  88.   gdb_byte *opaque_data;
  89. };

  90. static struct bookmark *bookmark_chain;
  91. static int bookmark_count;

  92. #define ALL_BOOKMARKS(B) for ((B) = bookmark_chain; (B); (B) = (B)->next)

  93. #define ALL_BOOKMARKS_SAFE(B,TMP)           \
  94.      for ((B) = bookmark_chain;             \
  95.           (B) ? ((TMP) = (B)->next, 1) : 0; \
  96.           (B) = (TMP))

  97. /* save_bookmark_command -- implement "bookmark" command.
  98.    Call target method to get a bookmark identifier.
  99.    Insert bookmark identifier into list.

  100.    Identifier will be a malloc string (gdb_byte *).
  101.    Up to us to free it as required.  */

  102. static void
  103. save_bookmark_command (char *args, int from_tty)
  104. {
  105.   /* Get target's idea of a bookmark.  */
  106.   gdb_byte *bookmark_id = target_get_bookmark (args, from_tty);
  107.   struct bookmark *b, *b1;
  108.   struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());

  109.   /* CR should not cause another identical bookmark.  */
  110.   dont_repeat ();

  111.   if (bookmark_id == NULL)
  112.     error (_("target_get_bookmark failed."));

  113.   /* Set up a bookmark struct.  */
  114.   b = xcalloc (1, sizeof (struct bookmark));
  115.   b->number = ++bookmark_count;
  116.   init_sal (&b->sal);
  117.   b->pc = regcache_read_pc (get_current_regcache ());
  118.   b->sal = find_pc_line (b->pc, 0);
  119.   b->sal.pspace = get_frame_program_space (get_current_frame ());
  120.   b->opaque_data = bookmark_id;
  121.   b->next = NULL;

  122.   /* Add this bookmark to the end of the chain, so that a list
  123.      of bookmarks will come out in order of increasing numbers.  */

  124.   b1 = bookmark_chain;
  125.   if (b1 == 0)
  126.     bookmark_chain = b;
  127.   else
  128.     {
  129.       while (b1->next)
  130.         b1 = b1->next;
  131.       b1->next = b;
  132.     }
  133.   printf_filtered (_("Saved bookmark %d at %s\n"), b->number,
  134.                      paddress (gdbarch, b->sal.pc));
  135. }

  136. /* Implement "delete bookmark" command.  */

  137. static int
  138. delete_one_bookmark (int num)
  139. {
  140.   struct bookmark *b1, *b;

  141.   /* Find bookmark with corresponding number.  */
  142.   ALL_BOOKMARKS (b)
  143.     if (b->number == num)
  144.       break;

  145.   /* Special case, first item in list.  */
  146.   if (b == bookmark_chain)
  147.     bookmark_chain = b->next;

  148.   /* Find bookmark preceding "marked" one, so we can unlink.  */
  149.   if (b)
  150.     {
  151.       ALL_BOOKMARKS (b1)
  152.         if (b1->next == b)
  153.           {
  154.             /* Found designated bookmark.  Unlink and delete.  */
  155.             b1->next = b->next;
  156.             break;
  157.           }
  158.       xfree (b->opaque_data);
  159.       xfree (b);
  160.       return 1;                /* success */
  161.     }
  162.   return 0;                /* failure */
  163. }

  164. static void
  165. delete_all_bookmarks (void)
  166. {
  167.   struct bookmark *b, *b1;

  168.   ALL_BOOKMARKS_SAFE (b, b1)
  169.     {
  170.       xfree (b->opaque_data);
  171.       xfree (b);
  172.     }
  173.   bookmark_chain = NULL;
  174. }

  175. static void
  176. delete_bookmark_command (char *args, int from_tty)
  177. {
  178.   int num;
  179.   struct get_number_or_range_state state;

  180.   if (bookmark_chain == NULL)
  181.     {
  182.       warning (_("No bookmarks."));
  183.       return;
  184.     }

  185.   if (args == NULL || args[0] == '\0')
  186.     {
  187.       if (from_tty && !query (_("Delete all bookmarks? ")))
  188.         return;
  189.       delete_all_bookmarks ();
  190.       return;
  191.     }

  192.   init_number_or_range (&state, args);
  193.   while (!state.finished)
  194.     {
  195.       num = get_number_or_range (&state);
  196.       if (!delete_one_bookmark (num))
  197.         /* Not found.  */
  198.         warning (_("No bookmark #%d."), num);
  199.     }
  200. }

  201. /* Implement "goto-bookmark" command.  */

  202. static void
  203. goto_bookmark_command (char *args, int from_tty)
  204. {
  205.   struct bookmark *b;
  206.   unsigned long num;
  207.   char *p = args;

  208.   if (args == NULL || args[0] == '\0')
  209.     error (_("Command requires an argument."));

  210.   if (strncmp (args, "start", strlen ("start")) == 0
  211.       || strncmp (args, "begin", strlen ("begin")) == 0
  212.       || strncmp (args, "end",   strlen ("end")) == 0)
  213.     {
  214.       /* Special case.  Give target opportunity to handle.  */
  215.       target_goto_bookmark ((gdb_byte *) args, from_tty);
  216.       return;
  217.     }

  218.   if (args[0] == '\'' || args[0] == '\"')
  219.     {
  220.       /* Special case -- quoted string.  Pass on to target.  */
  221.       if (args[strlen (args) - 1] != args[0])
  222.         error (_("Unbalanced quotes: %s"), args);
  223.       target_goto_bookmark ((gdb_byte *) args, from_tty);
  224.       return;
  225.     }

  226.   /* General case.  Bookmark identified by bookmark number.  */
  227.   num = get_number (&args);

  228.   if (num == 0)
  229.     error (_("goto-bookmark: invalid bookmark number '%s'."), p);

  230.   ALL_BOOKMARKS (b)
  231.     if (b->number == num)
  232.       break;

  233.   if (b)
  234.     {
  235.       /* Found.  Send to target method.  */
  236.       target_goto_bookmark (b->opaque_data, from_tty);
  237.       return;
  238.     }
  239.   /* Not found.  */
  240.   error (_("goto-bookmark: no bookmark found for '%s'."), p);
  241. }

  242. static int
  243. bookmark_1 (int bnum)
  244. {
  245.   struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
  246.   struct bookmark *b;
  247.   int matched = 0;

  248.   ALL_BOOKMARKS (b)
  249.   {
  250.     if (bnum == -1 || bnum == b->number)
  251.       {
  252.         printf_filtered ("   %d       %s    '%s'\n",
  253.                          b->number,
  254.                          paddress (gdbarch, b->pc),
  255.                          b->opaque_data);
  256.         matched++;
  257.       }
  258.   }

  259.   if (bnum > 0 && matched == 0)
  260.     printf_filtered ("No bookmark #%d\n", bnum);

  261.   return matched;
  262. }

  263. /* Implement "info bookmarks" command.  */

  264. static void
  265. bookmarks_info (char *args, int from_tty)
  266. {
  267.   int bnum = -1;

  268.   if (!bookmark_chain)
  269.     printf_filtered (_("No bookmarks.\n"));
  270.   else if (args == NULL || *args == '\0')
  271.     bookmark_1 (-1);
  272.   else
  273.     {
  274.       struct get_number_or_range_state state;

  275.       init_number_or_range (&state, args);
  276.       while (!state.finished)
  277.         {
  278.           bnum = get_number_or_range (&state);
  279.           bookmark_1 (bnum);
  280.         }
  281.     }
  282. }


  283. /* Provide a prototype to silence -Wmissing-prototypes.  */
  284. extern initialize_file_ftype _initialize_reverse;

  285. void
  286. _initialize_reverse (void)
  287. {
  288.   add_com ("reverse-step", class_run, reverse_step, _("\
  289. Step program backward until it reaches the beginning of another source line.\n\
  290. Argument N means do this N times (or till program stops for another reason).")
  291.            );
  292.   add_com_alias ("rs", "reverse-step", class_alias, 1);

  293.   add_com ("reverse-next", class_run, reverse_next, _("\
  294. Step program backward, proceeding through subroutine calls.\n\
  295. Like the \"reverse-step\" command as long as subroutine calls do not happen;\n\
  296. when they do, the call is treated as one instruction.\n\
  297. Argument N means do this N times (or till program stops for another reason).")
  298.            );
  299.   add_com_alias ("rn", "reverse-next", class_alias, 1);

  300.   add_com ("reverse-stepi", class_run, reverse_stepi, _("\
  301. Step backward exactly one instruction.\n\
  302. Argument N means do this N times (or till program stops for another reason).")
  303.            );
  304.   add_com_alias ("rsi", "reverse-stepi", class_alias, 0);

  305.   add_com ("reverse-nexti", class_run, reverse_nexti, _("\
  306. Step backward one instruction, but proceed through called subroutines.\n\
  307. Argument N means do this N times (or till program stops for another reason).")
  308.            );
  309.   add_com_alias ("rni", "reverse-nexti", class_alias, 0);

  310.   add_com ("reverse-continue", class_run, reverse_continue, _("\
  311. Continue program being debugged but run it in reverse.\n\
  312. If proceeding from breakpoint, a number N may be used as an argument,\n\
  313. which means to set the ignore count of that breakpoint to N - 1 (so that\n\
  314. the breakpoint won't break until the Nth time it is reached)."));
  315.   add_com_alias ("rc", "reverse-continue", class_alias, 0);

  316.   add_com ("reverse-finish", class_run, reverse_finish, _("\
  317. Execute backward until just before selected stack frame is called."));

  318.   add_com ("bookmark", class_bookmark, save_bookmark_command, _("\
  319. Set a bookmark in the program's execution history.\n\
  320. A bookmark represents a point in the execution history \n\
  321. that can be returned to at a later point in the debug session."));
  322.   add_info ("bookmarks", bookmarks_info, _("\
  323. Status of user-settable bookmarks.\n\
  324. Bookmarks are user-settable markers representing a point in the \n\
  325. execution history that can be returned to later in the same debug \n\
  326. session."));
  327.   add_cmd ("bookmark", class_bookmark, delete_bookmark_command, _("\
  328. Delete a bookmark from the bookmark list.\n\
  329. Argument is a bookmark number or numbers,\n\
  330. or no argument to delete all bookmarks.\n"),
  331.            &deletelist);
  332.   add_com ("goto-bookmark", class_bookmark, goto_bookmark_command, _("\
  333. Go to an earlier-bookmarked point in the program's execution history.\n\
  334. Argument is the bookmark number of a bookmark saved earlier by using \n\
  335. the 'bookmark' command, or the special arguments:\n\
  336.   start (beginning of recording)\n\
  337.   end   (end of recording)\n"));
  338. }