[PATCH] Running the inferior from breakpoint commands

Eli Zaretskii eliz@delorie.com
Wed Mar 15 08:25:00 GMT 2000


This is about the problem described in the following message:

  http://sourceware.cygnus.com/ml/gdb/2000-q1/msg00684.html

The relevant test cases are in gdb/testsuite/gdb.base/commands.exp.

Here are the patches which correct the problems I described in the
original message.  After applying them, the test program works as I'd
expect (and as commands.exp seems to want).

I didn't see any replies to my message, so I still don't know whether
the original code works for other platforms (I think it shouldn't).
Could someone please try commands.exp and tell what you get?

Please tell if it's okay to commit these changes.  If they are
accepted, I will also send changes for the docs, since I think there
are some limitations on what breakpoint commands can do that should be
documented.

2000-03-14  Eli Zaretskii  <eliz@is.elta.co.il>

	* breakpoint.c (breakpoint_alive_p): New function.
	(bpstat_do_actions): Allow recursive invocation, provided that the
	argument isn't identical to the one last seen.  Stop executing
	commands if their breakpoint no longer exists (e.g., was deleted
	by the previous command).  Save and restore the bpstat chain if
	the command proceeded the inferior.  Invoke bpstat_do_actions
	recursively to process the new bpstat produced when the proceeding
	inferior stops.

--- gdb/breakpoint.c~3	Wed Mar  8 20:02:20 2000
+++ gdb/breakpoint.c	Tue Mar 14 18:17:50 2000
@@ -1820,6 +1820,20 @@ bpstat_clear_actions (bs)
     }
 }
 
+/* Is the breakpoint BPT still defined?  */
+static int
+breakpoint_alive_p (bpt)
+     struct breakpoint *bpt;
+{
+  struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b == bpt)
+      return 1;
+
+  return 0;
+}
+
 /* Stub for cleaning up our state if we error-out of a breakpoint command */
 /* ARGSUSED */
 static void
@@ -1838,19 +1852,23 @@ void
 bpstat_do_actions (bsp)
      bpstat *bsp;
 {
-  bpstat bs;
+  static bpstat last_bpstat;
+  bpstat bs, saved_bs;
   struct cleanup *old_chain;
   struct command_line *cmd;
+  int bs_idx, cmd_idx;
 
   /* Avoid endless recursion if a `source' command is contained
      in bs->commands.  */
-  if (executing_breakpoint_commands)
+  if (executing_breakpoint_commands
+      && memcmp (bsp, &last_bpstat, sizeof (*bsp)) == 0)
     return;
 
+  last_bpstat = *bsp;
+
   executing_breakpoint_commands = 1;
   old_chain = make_cleanup (cleanup_executing_breakpoints, 0);
 
-top:
   /* Note that (as of this writing), our callers all appear to
      be passing us the address of global stop_bpstat.  And, if
      our calls to execute_control_command cause the inferior to
@@ -1863,26 +1881,78 @@ top:
   bs = *bsp;
 
   breakpoint_proceeded = 0;
-  for (; bs != NULL; bs = bs->next)
+  for (bs_idx = 0; bs != NULL; bs = bs->next, bs_idx++)
     {
+      /* If someone deleted the breakpoint associated with this
+	 bpstat, we cannot run its commands, since deleting a
+	 breakpoint nukes its command lines.  */
+      if (!breakpoint_alive_p (bs->breakpoint_at))
+	continue;
       cmd = bs->commands;
+      cmd_idx = 0;
       while (cmd != NULL)
 	{
+	  struct cleanup *pchain;
+	  int idx;
+
+	  saved_bs = bpstat_copy (*bsp);
+	  pchain = make_cleanup ((make_cleanup_func)bpstat_clear, &saved_bs);
 	  execute_control_command (cmd);
 
 	  if (breakpoint_proceeded)
+	    {
+	      /* The inferior is proceeded by the command.  We cannot
+		 continue, as the bpstat chain has been blown away by
+		 wait_for_inferior.  But since execution has stopped
+		 again, there is a new bpstat to look at, so start
+		 over.  */
+	      bpstat_do_actions (bsp);
+
+	      /* Now we need to proceed with any actions of the old
+		 bpstat chain which are still not done.  But first, we
+		 need to restore the old chain, since it was blown
+		 away.  */
+	      *bsp = saved_bs;
+	      bs = *bsp;
+	      last_bpstat = *bsp;
+
+	      /* Recursive invocation of bpstat_do_actions could reset
+		 breakpoint_proceeded and
+		 executing_breakpoint_commands, so restore their
+		 values.  */
+	      breakpoint_proceeded = 1;
+	      executing_breakpoint_commands = 1;
+
+	      /* Skip all the actions that were already done.  */
+	      for (idx = 0; idx < bs_idx; idx++)
+		{
+		  bs->commands = NULL;
+		  bs = bs->next;
+		}
+	      cmd = bs->commands;
+	    }
+	  else
+	    {
+	      bpstat_clear (&saved_bs);
+	      discard_cleanups (pchain);
+	    }
+	  cmd_idx++;
+	  /* The command we just ran could have deleted the
+	     breakpoint.  This nukes the command lines for this
+	     breakpoint, so we cannot continue them.  */
+	  if (!breakpoint_alive_p (bs->breakpoint_at))
 	    break;
+	  if (breakpoint_proceeded)
+	    {
+	      /* Skip the commands we already ran.  */
+	      for (idx = 0; idx < cmd_idx; idx++)
+		cmd = cmd->next;
+	      breakpoint_proceeded = 0;
+	    }
 	  else
 	    cmd = cmd->next;
 	}
-      if (breakpoint_proceeded)
-	/* The inferior is proceeded by the command; bomb out now.
-	   The bpstat chain has been blown away by wait_for_inferior.
-	   But since execution has stopped again, there is a new bpstat
-	   to look at, so start over.  */
-	goto top;
-      else
-	bs->commands = NULL;
+      bs->commands = NULL;
     }
 
   executing_breakpoint_commands = 0;



More information about the Gdb-patches mailing list