public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [2/2] RFC: let "commands" affect multiple breakpoints
@ 2010-03-10  3:54 Tom Tromey
  2010-03-10 16:34 ` Tom Tromey
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Tom Tromey @ 2010-03-10  3:54 UTC (permalink / raw)
  To: gdb-patches

I'd appreciate comments on this.  Barring comments I will commit it
soonish.  It needs a doc review.

This patch changes "commands" in two ways.  First, it lets "commands"
accept a breakpoint range, like "enable".  With no arguments it mostly
acts like it did before; except if the previous command was "rbreak"
then this form will affect all the breakpoints that were just set.

This is PR 9352.

Built and regtested on x86-64 (compile farm).

Tom

2010-03-09  Tom Tromey  <tromey@redhat.com>

	PR breakpoints/9352:
	* NEWS: Mention changes to `commands' and `rbreak'.
	* symtab.c (do_end_rbreak_breakpoints): New function.
	(rbreak_command): Call start_rbreak_breakpoints; arrange to call
	end_rbreak_breakpoints.
	* breakpoint.c (breakpoint_count, tracepoint_count): Now static.
	(set_breakpoint_count): Likewise.  Clear last_was_rbreak.
	(rbreak_start, rbreak_end, last_was_rbreak): New globals.
	(start_rbreak_breakpoints, end_rbreak_breakpoints): New
	functions.
	(struct commands_info): New
	(do_map_commands_command): New function.
	(commands_command_1): New function.
	(commands_command): Use it.
	(commands_from_control_command): Likewise.
	(do_delete_breakpoint): New function.
	(delete_command): Use it.
	(map_breakpoint_numbers): Add 'data' argument.  Pass to callback.
	(do_map_disable_breakpoint): New function.
	(disable_command): Use it.
	(do_map_enable_breakpoint): New function.
	(enable_command): Use it.
	(enable_once_breakpoint): Add argument.
	(enable_once_command): Update.
	(enable_delete_breakpoint): Add argument.
	(enable_delete_command): Update.
	* breakpoint.h (start_rbreak_breakpoints, end_rbreak_breakpoints):
	Declare.

2010-03-09  Tom Tromey  <tromey@redhat.com>

	PR breakpoints/9352:
	* gdb.texinfo (Set Breaks): Update.

2010-03-09  Tom Tromey  <tromey@redhat.com>

	PR breakpoints/9352:
	* gdb.base/default.exp: Update.
	* gdb.base/commands.exp: Update.

diff --git a/gdb/NEWS b/gdb/NEWS
index 6cec32a..107aeba 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,10 @@
 
 *** Changes since GDB 7.1
 
+* The `commands' command now accepts a range of breakpoints to modify.
+  A plain `commands' following an `rbreak' will affect all the
+  breakpoints set by `rbreak'.
+
 * Python scripting
 
 The GDB Python API now has access to symbols, symbol tables, and
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index e817a23..e7f5823 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -79,17 +79,15 @@
 
 static void enable_delete_command (char *, int);
 
-static void enable_delete_breakpoint (struct breakpoint *);
-
 static void enable_once_command (char *, int);
 
-static void enable_once_breakpoint (struct breakpoint *);
-
 static void disable_command (char *, int);
 
 static void enable_command (char *, int);
 
-static void map_breakpoint_numbers (char *, void (*)(struct breakpoint *));
+static void map_breakpoint_numbers (char *, void (*) (struct breakpoint *,
+						      void *),
+				    void *);
 
 static void ignore_command (char *, int);
 
@@ -146,8 +144,6 @@ static void condition_command (char *, int);
 
 static int get_number_trailer (char **, int);
 
-void set_breakpoint_count (int);
-
 typedef enum
   {
     mark_inserted,
@@ -390,11 +386,18 @@ VEC(bp_location_p) *moribund_locations = NULL;
 
 /* Number of last breakpoint made.  */
 
-int breakpoint_count;
+static int breakpoint_count;
+
+/* If the last command to create a breakpoint was "rbreak", this holds
+   the start and end breakpoint numbers.  */
+static int rbreak_start;
+static int rbreak_end;
+/* True if the last breakpoint was made with "rbreak".  */
+static int last_was_rbreak;
 
 /* Number of last tracepoint made.  */
 
-int tracepoint_count;
+static int tracepoint_count;
 
 /* Return whether a breakpoint is an active enabled breakpoint.  */
 static int
@@ -405,13 +408,34 @@ breakpoint_enabled (struct breakpoint *b)
 
 /* Set breakpoint count to NUM.  */
 
-void
+static void
 set_breakpoint_count (int num)
 {
   breakpoint_count = num;
+  last_was_rbreak = 0;
   set_internalvar_integer (lookup_internalvar ("bpnum"), num);
 }
 
+/* Called at the start an "rbreak" command to record the first
+   breakpoint made.  */
+void
+start_rbreak_breakpoints (void)
+{
+  rbreak_start = breakpoint_count + 1;
+}
+
+/* Called at the end of an "rbreak" command to record the last
+   breakpoint made.  */
+void
+end_rbreak_breakpoints (void)
+{
+  if (breakpoint_count >= rbreak_start)
+    {
+      rbreak_end = breakpoint_count;
+      last_was_rbreak = 1;
+    }
+}
+
 /* Used in run_command to zero the hit count when a new run starts. */
 
 void
@@ -747,32 +771,86 @@ breakpoint_set_commands (struct breakpoint *b, struct command_line *commands)
   observer_notify_breakpoint_modified (b->number);
 }
 
+/* A structure used to pass information through
+   map_breakpoint_numbers.  */
+
+struct commands_info
+{
+  /* True if the command was typed at a tty.  */
+  int from_tty;
+  /* Non-NULL if the body of the commands are being read from this
+     already-parsed command.  */
+  struct command_line *control;
+  /* The command lines read from the user, or NULL if they have not
+     yet been read.  */
+  struct counted_command_line *cmd;
+};
+
+/* A callback for map_breakpoint_numbers that sets the commands for
+   commands_command.  */
+
 static void
-commands_command (char *arg, int from_tty)
+do_map_commands_command (struct breakpoint *b, void *data)
 {
-  struct breakpoint *b;
-  char *p;
-  int bnum;
-  struct command_line *l;
+  struct commands_info *info = data;
 
-  p = arg;
-  bnum = get_number (&p);
+  if (info->cmd == NULL)
+    {
+      struct command_line *l;
+      if (info->control != NULL)
+	l = copy_command_lines (info->control->body_list[0]);
+      else
+	l = read_command_lines (_("Type commands for all specified breakpoints"),
+				info->from_tty, 1);
+      info->cmd = alloc_counted_command_line (l);
+    }
+
+  /* If a breakpoint was on the list more than once, we don't need to
+     do anything.  */
+  if (b->commands != info->cmd)
+    {
+      incref_counted_command_line (info->cmd);
+      decref_counted_command_line (&b->commands);
+      b->commands = info->cmd;
+      breakpoints_changed ();
+      observer_notify_breakpoint_modified (b->number);
+    }
+}
 
-  if (p && *p)
-    error (_("Unexpected extra arguments following breakpoint number."));
+static void
+commands_command_1 (char *arg, int from_tty, struct command_line *control)
+{
+  struct cleanup *cleanups;
+  struct commands_info info;
 
-  ALL_BREAKPOINTS (b)
-    if (b->number == bnum)
-      {
-	char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.", 
-				 bnum);
-	struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
-	l = read_command_lines (tmpbuf, from_tty, 1);
-	do_cleanups (cleanups);
-	breakpoint_set_commands (b, l);
-	return;
+  info.from_tty = from_tty;
+  info.control = control;
+  info.cmd = NULL;
+  /* If we read command lines from the user, then `info' will hold an
+     extra reference to the commands that we must clean up.  */
+  cleanups = make_cleanup_decref_counted_command_line (&info.cmd);
+
+  if (arg == NULL || !*arg)
+    {
+      if (last_was_rbreak)
+	arg = xstrprintf ("%d-%d", rbreak_start, rbreak_end);
+      else if (breakpoint_count > 0)
+	arg = xstrprintf ("%d", breakpoint_count);
+      make_cleanup (xfree, arg);
     }
-  error (_("No breakpoint number %d."), bnum);
+
+  map_breakpoint_numbers (arg, do_map_commands_command, &info);
+
+  if (info.cmd == NULL)
+    error (_("No breakpoints specified."));
+
+  do_cleanups (cleanups);
+}
+
+static void
+commands_command (char *arg, int from_tty)
+{
+  commands_command_1 (arg, from_tty, NULL);
 }
 
 /* Like commands_command, but instead of reading the commands from
@@ -783,36 +861,8 @@ commands_command (char *arg, int from_tty)
 enum command_control_type
 commands_from_control_command (char *arg, struct command_line *cmd)
 {
-  struct breakpoint *b;
-  char *p;
-  int bnum;
-
-  /* An empty string for the breakpoint number means the last
-     breakpoint, but get_number expects a NULL pointer.  */
-  if (arg && !*arg)
-    p = NULL;
-  else
-    p = arg;
-  bnum = get_number (&p);
-
-  if (p && *p)
-    error (_("Unexpected extra arguments following breakpoint number."));
-
-  ALL_BREAKPOINTS (b)
-    if (b->number == bnum)
-      {
-	decref_counted_command_line (&b->commands);
-	if (cmd->body_count != 1)
-	  error (_("Invalid \"commands\" block structure."));
-	/* We need to copy the commands because if/while will free the
-	   list after it finishes execution.  */
-	b->commands
-	  = alloc_counted_command_line (copy_command_lines (cmd->body_list[0]));
-	breakpoints_changed ();
-	observer_notify_breakpoint_modified (b->number);
-	return simple_control;
-      }
-  error (_("No breakpoint number %d."), bnum);
+  commands_command_1 (arg, 0, cmd);
+  return simple_control;
 }
 
 /* Return non-zero if BL->TARGET_INFO contains valid information.  */
@@ -8950,6 +9000,15 @@ make_cleanup_delete_breakpoint (struct breakpoint *b)
   return make_cleanup (do_delete_breakpoint_cleanup, b);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   delete_breakpoint.  */
+
+static void
+do_delete_breakpoint (struct breakpoint *b, void *ignore)
+{
+  delete_breakpoint (b);
+}
+
 void
 delete_command (char *arg, int from_tty)
 {
@@ -8997,7 +9056,7 @@ delete_command (char *arg, int from_tty)
 	}
     }
   else
-    map_breakpoint_numbers (arg, delete_breakpoint);
+    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
 }
 
 static int
@@ -9458,7 +9517,9 @@ ignore_command (char *args, int from_tty)
    whose numbers are given in ARGS.  */
 
 static void
-map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
+map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *,
+						      void *),
+			void *data)
 {
   char *p = args;
   char *p1;
@@ -9486,9 +9547,9 @@ map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
 	      {
 		struct breakpoint *related_breakpoint = b->related_breakpoint;
 		match = 1;
-		function (b);
+		function (b, data);
 		if (related_breakpoint)
-		  function (related_breakpoint);
+		  function (related_breakpoint, data);
 		break;
 	      }
 	  if (match == 0)
@@ -9564,6 +9625,15 @@ disable_breakpoint (struct breakpoint *bpt)
   observer_notify_breakpoint_modified (bpt->number);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   disable_breakpoint.  */
+
+static void
+do_map_disable_breakpoint (struct breakpoint *b, void *ignore)
+{
+  disable_breakpoint (b);
+}
+
 static void
 disable_command (char *args, int from_tty)
 {
@@ -9597,7 +9667,7 @@ disable_command (char *args, int from_tty)
       update_global_location_list (0);
     }
   else
-    map_breakpoint_numbers (args, disable_breakpoint);
+    map_breakpoint_numbers (args, do_map_disable_breakpoint, NULL);
 }
 
 static void
@@ -9654,6 +9724,15 @@ enable_breakpoint (struct breakpoint *bpt)
   do_enable_breakpoint (bpt, bpt->disposition);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   enable_breakpoint.  */
+
+static void
+do_map_enable_breakpoint (struct breakpoint *b, void *ignore)
+{
+  enable_breakpoint (b);
+}
+
 /* The enable command enables the specified breakpoints (or all defined
    breakpoints) so they once again become (or continue to be) effective
    in stopping the inferior.  */
@@ -9691,11 +9770,11 @@ enable_command (char *args, int from_tty)
       update_global_location_list (1);
     }
   else
-    map_breakpoint_numbers (args, enable_breakpoint);
+    map_breakpoint_numbers (args, do_map_enable_breakpoint, NULL);
 }
 
 static void
-enable_once_breakpoint (struct breakpoint *bpt)
+enable_once_breakpoint (struct breakpoint *bpt, void *ignore)
 {
   do_enable_breakpoint (bpt, disp_disable);
 }
@@ -9703,11 +9782,11 @@ enable_once_breakpoint (struct breakpoint *bpt)
 static void
 enable_once_command (char *args, int from_tty)
 {
-  map_breakpoint_numbers (args, enable_once_breakpoint);
+  map_breakpoint_numbers (args, enable_once_breakpoint, NULL);
 }
 
 static void
-enable_delete_breakpoint (struct breakpoint *bpt)
+enable_delete_breakpoint (struct breakpoint *bpt, void *ignore)
 {
   do_enable_breakpoint (bpt, disp_del);
 }
@@ -9715,7 +9794,7 @@ enable_delete_breakpoint (struct breakpoint *bpt)
 static void
 enable_delete_command (char *args, int from_tty)
 {
-  map_breakpoint_numbers (args, enable_delete_breakpoint);
+  map_breakpoint_numbers (args, enable_delete_breakpoint, NULL);
 }
 \f
 static void
@@ -10138,7 +10217,7 @@ delete_trace_command (char *arg, int from_tty)
 	}
     }
   else
-    map_breakpoint_numbers (arg, delete_breakpoint);
+    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
 }
 
 /* Set passcount for tracepoint.
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 1480991..8e36f21 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1012,4 +1012,9 @@ extern struct breakpoint *get_tracepoint_by_number (char **arg, int multi_p,
    is newly allocated; the caller should free when done with it.  */
 extern VEC(breakpoint_p) *all_tracepoints (void);
 
+/* Call at the start and end of an "rbreak" command to register
+   breakpoint numbers for a later "commands" command.  */
+extern void start_rbreak_breakpoints (void);
+extern void end_rbreak_breakpoints (void);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index f6105b7..557316a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4326,19 +4326,21 @@ enable other breakpoints.
 @table @code
 @kindex commands
 @kindex end@r{ (breakpoint commands)}
-@item commands @r{[}@var{bnum}@r{]}
+@item commands @r{[}@var{range}@dots{}@r{]}
 @itemx @dots{} @var{command-list} @dots{}
 @itemx end
-Specify a list of commands for breakpoint number @var{bnum}.  The commands
+Specify a list of commands for the given breakpoints.  The commands
 themselves appear on the following lines.  Type a line containing just
 @code{end} to terminate the commands.
 
 To remove all commands from a breakpoint, type @code{commands} and
 follow it immediately with @code{end}; that is, give no commands.
 
-With no @var{bnum} argument, @code{commands} refers to the last
-breakpoint, watchpoint, or catchpoint set (not to the breakpoint most
-recently encountered).
+With no argument, @code{commands} refers to the last breakpoint,
+watchpoint, or catchpoint set (not to the breakpoint most recently
+encountered).  If the most recent breakpoints were set with an
+@command{rbreak} command, then the @code{commands} will apply to all
+the breakpoints set by that @command{rbreak}.
 @end table
 
 Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
diff --git a/gdb/symtab.c b/gdb/symtab.c
index af4e501..e9a3c0f 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3610,23 +3610,41 @@ rbreak_command_wrapper (char *regexp, int from_tty)
   rbreak_command (regexp, from_tty);
 }
 
+/* A cleanup function that calls end_rbreak_breakpoints.  */
+
+static void
+do_end_rbreak_breakpoints (void *ignore)
+{
+  end_rbreak_breakpoints ();
+}
+
 static void
 rbreak_command (char *regexp, int from_tty)
 {
   struct symbol_search *ss;
   struct symbol_search *p;
   struct cleanup *old_chain;
+  char *string = NULL;
+  int len = 0;
 
   search_symbols (regexp, FUNCTIONS_DOMAIN, 0, (char **) NULL, &ss);
   old_chain = make_cleanup_free_search_symbols (ss);
+  make_cleanup (free_current_contents, &string);
 
+  start_rbreak_breakpoints ();
+  make_cleanup (do_end_rbreak_breakpoints, NULL);
   for (p = ss; p != NULL; p = p->next)
     {
       if (p->msymbol == NULL)
 	{
-	  char *string = alloca (strlen (p->symtab->filename)
-				 + strlen (SYMBOL_LINKAGE_NAME (p->symbol))
-				 + 4);
+	  int newlen = (strlen (p->symtab->filename)
+			+ strlen (SYMBOL_LINKAGE_NAME (p->symbol))
+			+ 4);
+	  if (newlen > len)
+	    {
+	      string = xrealloc (string, newlen);
+	      len = newlen;
+	    }
 	  strcpy (string, p->symtab->filename);
 	  strcat (string, ":'");
 	  strcat (string, SYMBOL_LINKAGE_NAME (p->symbol));
@@ -3640,8 +3658,13 @@ rbreak_command (char *regexp, int from_tty)
 	}
       else
 	{
-	  char *string = alloca (strlen (SYMBOL_LINKAGE_NAME (p->msymbol))
-				 + 3);
+	  int newlen = (strlen (SYMBOL_LINKAGE_NAME (p->msymbol))
+			+ 3);
+	  if (newlen > len)
+	    {
+	      string = xrealloc (string, newlen);
+	      len = newlen;
+	    }
 	  strcpy (string, "'");
 	  strcat (string, SYMBOL_LINKAGE_NAME (p->msymbol));
 	  strcat (string, "'");
diff --git a/gdb/testsuite/gdb.base/commands.exp b/gdb/testsuite/gdb.base/commands.exp
index b3257aa..6514e81 100644
--- a/gdb/testsuite/gdb.base/commands.exp
+++ b/gdb/testsuite/gdb.base/commands.exp
@@ -299,7 +299,7 @@ proc watchpoint_command_test {} {
 
     send_gdb "commands $wp_id\n"
     gdb_expect {
-      -re "Type commands for when breakpoint $wp_id is hit, one per line.*>" {
+      -re "Type commands for all specified breakpoints.*>" {
 	  pass "begin commands on watch"
       }
       -re "$gdb_prompt $" {fail "begin commands on watch"}
@@ -452,7 +452,7 @@ proc bp_deleted_in_command_test {} {
     
     send_gdb "commands\n"
     gdb_expect {
-      -re "Type commands for when breakpoint .* is hit, one per line.*>" {
+      -re "Type commands for all specified breakpoints.*>" {
           pass "begin commands in bp_deleted_in_command_test"
       }
       -re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
@@ -519,7 +519,7 @@ proc temporary_breakpoint_commands {} {
     
     send_gdb "commands\n"
     gdb_expect {
-	-re "Type commands for when breakpoint .* is hit, one per line.*>" {
+	-re "Type commands for all specified breakpoints.*>" {
 	    pass "begin commands in bp_deleted_in_command_test"
 	}
 	-re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index 9603fd4..3a7e1e8 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -100,7 +100,7 @@ gdb_test "cd" "Argument required .new working directory.*" "cd"
 gdb_test "clear" "No source file specified..*" "clear"
 
 #test commands
-gdb_test "commands" "No breakpoint number 0..*" "commands"
+gdb_test "commands" "Argument required .one or more breakpoint numbers...*" "commands"
 
 #test condition
 gdb_test "condition" "Argument required .breakpoint number.*" "condition"

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-10  3:54 [2/2] RFC: let "commands" affect multiple breakpoints Tom Tromey
@ 2010-03-10 16:34 ` Tom Tromey
  2010-03-10 17:05 ` Pedro Alves
  2010-03-10 17:37 ` Eli Zaretskii
  2 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2010-03-10 16:34 UTC (permalink / raw)
  To: gdb-patches

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Tom> I'd appreciate comments on this.  Barring comments I will commit it
Tom> soonish.  It needs a doc review.

Actually, this patch is a little half-baked.  I forgot (sigh) to write
any tests... so I won't be committing it until I do that.

I do have a question though.  With this change, gdb prints somewhat less
nice text for "commands":

Tom> +	l = read_command_lines (_("Type commands for all specified breakpoints"),
Tom> +				info->from_tty, 1);

Tom> -	char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.", 
Tom> -				 bnum);

Any suggestions for something better here?

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-10  3:54 [2/2] RFC: let "commands" affect multiple breakpoints Tom Tromey
  2010-03-10 16:34 ` Tom Tromey
@ 2010-03-10 17:05 ` Pedro Alves
  2010-03-11 21:42   ` Tom Tromey
  2010-03-10 17:37 ` Eli Zaretskii
  2 siblings, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2010-03-10 17:05 UTC (permalink / raw)
  To: gdb-patches, tromey

On Wednesday 10 March 2010 03:54:28, Tom Tromey wrote:
> I'd appreciate comments on this.  Barring comments I will commit it
> soonish.  It needs a doc review.
> This patch changes "commands" in two ways.  First, it lets "commands"
> accept a breakpoint range, like "enable".  With no arguments it mostly
> acts like it did before; except if the previous command was "rbreak"
> then this form will affect all the breakpoints that were just set.

I'm okay with change.  I only skimmed throught the patch, but
I was wondering if it should be generalized to not be specific 
to rbreak only, but to all cases we create more than one
breakpoint with a single command?  For example, using
gdb.cp/overload,

 (gdb) b foo::foo
 Breakpoint 2 at 0x4007fc: file ../../../src/gdb/testsuite/gdb.cp/overload.cc, line 135. (2 locations)
 Breakpoint 3 at 0x4007b3: file ../../../src/gdb/testsuite/gdb.cp/overload.cc, line 134. (2 locations)
 Breakpoint 4 at 0x40076b: file ../../../src/gdb/testsuite/gdb.cp/overload.cc, line 133. (2 locations)
 warning: Multiple breakpoints were set.
 Use the "delete" command to delete unwanted breakpoints.
 (gdb)

Just curious if you considered it, and decided against it.

> 
> This is PR 9352.
> 
> Built and regtested on x86-64 (compile farm).
> 
> Tom
> 
> 2010-03-09  Tom Tromey  <tromey@redhat.com>
> 
> 	PR breakpoints/9352:
> 	* NEWS: Mention changes to `commands' and `rbreak'.
> 	* symtab.c (do_end_rbreak_breakpoints): New function.
> 	(rbreak_command): Call start_rbreak_breakpoints; arrange to call
> 	end_rbreak_breakpoints.
> 	* breakpoint.c (breakpoint_count, tracepoint_count): Now static.
> 	(set_breakpoint_count): Likewise.  Clear last_was_rbreak.
> 	(rbreak_start, rbreak_end, last_was_rbreak): New globals.
> 	(start_rbreak_breakpoints, end_rbreak_breakpoints): New
> 	functions.
> 	(struct commands_info): New
> 	(do_map_commands_command): New function.
> 	(commands_command_1): New function.
> 	(commands_command): Use it.
> 	(commands_from_control_command): Likewise.
> 	(do_delete_breakpoint): New function.
> 	(delete_command): Use it.
> 	(map_breakpoint_numbers): Add 'data' argument.  Pass to callback.
> 	(do_map_disable_breakpoint): New function.
> 	(disable_command): Use it.
> 	(do_map_enable_breakpoint): New function.
> 	(enable_command): Use it.
> 	(enable_once_breakpoint): Add argument.
> 	(enable_once_command): Update.
> 	(enable_delete_breakpoint): Add argument.
> 	(enable_delete_command): Update.
> 	* breakpoint.h (start_rbreak_breakpoints, end_rbreak_breakpoints):
> 	Declare.
> 
> 2010-03-09  Tom Tromey  <tromey@redhat.com>
> 
> 	PR breakpoints/9352:
> 	* gdb.texinfo (Set Breaks): Update.
> 
> 2010-03-09  Tom Tromey  <tromey@redhat.com>
> 
> 	PR breakpoints/9352:
> 	* gdb.base/default.exp: Update.
> 	* gdb.base/commands.exp: Update.
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 6cec32a..107aeba 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,10 @@
>  
>  *** Changes since GDB 7.1
>  
> +* The `commands' command now accepts a range of breakpoints to modify.
> +  A plain `commands' following an `rbreak' will affect all the
> +  breakpoints set by `rbreak'.
> +
>  * Python scripting
>  
>  The GDB Python API now has access to symbols, symbol tables, and
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index e817a23..e7f5823 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -79,17 +79,15 @@
>  
>  static void enable_delete_command (char *, int);
>  
> -static void enable_delete_breakpoint (struct breakpoint *);
> -
>  static void enable_once_command (char *, int);
>  
> -static void enable_once_breakpoint (struct breakpoint *);
> -
>  static void disable_command (char *, int);
>  
>  static void enable_command (char *, int);
>  
> -static void map_breakpoint_numbers (char *, void (*)(struct breakpoint *));
> +static void map_breakpoint_numbers (char *, void (*) (struct breakpoint *,
> +						      void *),
> +				    void *);
>  
>  static void ignore_command (char *, int);
>  
> @@ -146,8 +144,6 @@ static void condition_command (char *, int);
>  
>  static int get_number_trailer (char **, int);
>  
> -void set_breakpoint_count (int);
> -
>  typedef enum
>    {
>      mark_inserted,
> @@ -390,11 +386,18 @@ VEC(bp_location_p) *moribund_locations = NULL;
>  
>  /* Number of last breakpoint made.  */
>  
> -int breakpoint_count;
> +static int breakpoint_count;
> +
> +/* If the last command to create a breakpoint was "rbreak", this holds
> +   the start and end breakpoint numbers.  */
> +static int rbreak_start;
> +static int rbreak_end;
> +/* True if the last breakpoint was made with "rbreak".  */
> +static int last_was_rbreak;
>  
>  /* Number of last tracepoint made.  */
>  
> -int tracepoint_count;
> +static int tracepoint_count;
>  
>  /* Return whether a breakpoint is an active enabled breakpoint.  */
>  static int
> @@ -405,13 +408,34 @@ breakpoint_enabled (struct breakpoint *b)
>  
>  /* Set breakpoint count to NUM.  */
>  
> -void
> +static void
>  set_breakpoint_count (int num)
>  {
>    breakpoint_count = num;
> +  last_was_rbreak = 0;
>    set_internalvar_integer (lookup_internalvar ("bpnum"), num);
>  }
>  
> +/* Called at the start an "rbreak" command to record the first
> +   breakpoint made.  */
> +void
> +start_rbreak_breakpoints (void)
> +{
> +  rbreak_start = breakpoint_count + 1;
> +}
> +
> +/* Called at the end of an "rbreak" command to record the last
> +   breakpoint made.  */
> +void
> +end_rbreak_breakpoints (void)
> +{
> +  if (breakpoint_count >= rbreak_start)
> +    {
> +      rbreak_end = breakpoint_count;
> +      last_was_rbreak = 1;
> +    }
> +}
> +
>  /* Used in run_command to zero the hit count when a new run starts. */
>  
>  void
> @@ -747,32 +771,86 @@ breakpoint_set_commands (struct breakpoint *b, struct command_line *commands)
>    observer_notify_breakpoint_modified (b->number);
>  }
>  
> +/* A structure used to pass information through
> +   map_breakpoint_numbers.  */
> +
> +struct commands_info
> +{
> +  /* True if the command was typed at a tty.  */
> +  int from_tty;
> +  /* Non-NULL if the body of the commands are being read from this
> +     already-parsed command.  */
> +  struct command_line *control;
> +  /* The command lines read from the user, or NULL if they have not
> +     yet been read.  */
> +  struct counted_command_line *cmd;
> +};
> +
> +/* A callback for map_breakpoint_numbers that sets the commands for
> +   commands_command.  */
> +
>  static void
> -commands_command (char *arg, int from_tty)
> +do_map_commands_command (struct breakpoint *b, void *data)
>  {
> -  struct breakpoint *b;
> -  char *p;
> -  int bnum;
> -  struct command_line *l;
> +  struct commands_info *info = data;
>  
> -  p = arg;
> -  bnum = get_number (&p);
> +  if (info->cmd == NULL)
> +    {
> +      struct command_line *l;
> +      if (info->control != NULL)
> +	l = copy_command_lines (info->control->body_list[0]);
> +      else
> +	l = read_command_lines (_("Type commands for all specified breakpoints"),
> +				info->from_tty, 1);
> +      info->cmd = alloc_counted_command_line (l);
> +    }
> +
> +  /* If a breakpoint was on the list more than once, we don't need to
> +     do anything.  */
> +  if (b->commands != info->cmd)
> +    {
> +      incref_counted_command_line (info->cmd);
> +      decref_counted_command_line (&b->commands);
> +      b->commands = info->cmd;
> +      breakpoints_changed ();
> +      observer_notify_breakpoint_modified (b->number);
> +    }
> +}
>  
> -  if (p && *p)
> -    error (_("Unexpected extra arguments following breakpoint number."));
> +static void
> +commands_command_1 (char *arg, int from_tty, struct command_line *control)
> +{
> +  struct cleanup *cleanups;
> +  struct commands_info info;
>  
> -  ALL_BREAKPOINTS (b)
> -    if (b->number == bnum)
> -      {
> -	char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.", 
> -				 bnum);
> -	struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
> -	l = read_command_lines (tmpbuf, from_tty, 1);
> -	do_cleanups (cleanups);
> -	breakpoint_set_commands (b, l);
> -	return;
> +  info.from_tty = from_tty;
> +  info.control = control;
> +  info.cmd = NULL;
> +  /* If we read command lines from the user, then `info' will hold an
> +     extra reference to the commands that we must clean up.  */
> +  cleanups = make_cleanup_decref_counted_command_line (&info.cmd);
> +
> +  if (arg == NULL || !*arg)
> +    {
> +      if (last_was_rbreak)
> +	arg = xstrprintf ("%d-%d", rbreak_start, rbreak_end);
> +      else if (breakpoint_count > 0)
> +	arg = xstrprintf ("%d", breakpoint_count);
> +      make_cleanup (xfree, arg);
>      }
> -  error (_("No breakpoint number %d."), bnum);
> +
> +  map_breakpoint_numbers (arg, do_map_commands_command, &info);
> +
> +  if (info.cmd == NULL)
> +    error (_("No breakpoints specified."));
> +
> +  do_cleanups (cleanups);
> +}
> +
> +static void
> +commands_command (char *arg, int from_tty)
> +{
> +  commands_command_1 (arg, from_tty, NULL);
>  }
>  
>  /* Like commands_command, but instead of reading the commands from
> @@ -783,36 +861,8 @@ commands_command (char *arg, int from_tty)
>  enum command_control_type
>  commands_from_control_command (char *arg, struct command_line *cmd)
>  {
> -  struct breakpoint *b;
> -  char *p;
> -  int bnum;
> -
> -  /* An empty string for the breakpoint number means the last
> -     breakpoint, but get_number expects a NULL pointer.  */
> -  if (arg && !*arg)
> -    p = NULL;
> -  else
> -    p = arg;
> -  bnum = get_number (&p);
> -
> -  if (p && *p)
> -    error (_("Unexpected extra arguments following breakpoint number."));
> -
> -  ALL_BREAKPOINTS (b)
> -    if (b->number == bnum)
> -      {
> -	decref_counted_command_line (&b->commands);
> -	if (cmd->body_count != 1)
> -	  error (_("Invalid \"commands\" block structure."));
> -	/* We need to copy the commands because if/while will free the
> -	   list after it finishes execution.  */
> -	b->commands
> -	  = alloc_counted_command_line (copy_command_lines (cmd->body_list[0]));
> -	breakpoints_changed ();
> -	observer_notify_breakpoint_modified (b->number);
> -	return simple_control;
> -      }
> -  error (_("No breakpoint number %d."), bnum);
> +  commands_command_1 (arg, 0, cmd);
> +  return simple_control;
>  }
>  
>  /* Return non-zero if BL->TARGET_INFO contains valid information.  */
> @@ -8950,6 +9000,15 @@ make_cleanup_delete_breakpoint (struct breakpoint *b)
>    return make_cleanup (do_delete_breakpoint_cleanup, b);
>  }
>  
> +/* A callback for map_breakpoint_numbers that calls
> +   delete_breakpoint.  */
> +
> +static void
> +do_delete_breakpoint (struct breakpoint *b, void *ignore)
> +{
> +  delete_breakpoint (b);
> +}
> +
>  void
>  delete_command (char *arg, int from_tty)
>  {
> @@ -8997,7 +9056,7 @@ delete_command (char *arg, int from_tty)
>  	}
>      }
>    else
> -    map_breakpoint_numbers (arg, delete_breakpoint);
> +    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
>  }
>  
>  static int
> @@ -9458,7 +9517,9 @@ ignore_command (char *args, int from_tty)
>     whose numbers are given in ARGS.  */
>  
>  static void
> -map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
> +map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *,
> +						      void *),
> +			void *data)
>  {
>    char *p = args;
>    char *p1;
> @@ -9486,9 +9547,9 @@ map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
>  	      {
>  		struct breakpoint *related_breakpoint = b->related_breakpoint;
>  		match = 1;
> -		function (b);
> +		function (b, data);
>  		if (related_breakpoint)
> -		  function (related_breakpoint);
> +		  function (related_breakpoint, data);
>  		break;
>  	      }
>  	  if (match == 0)
> @@ -9564,6 +9625,15 @@ disable_breakpoint (struct breakpoint *bpt)
>    observer_notify_breakpoint_modified (bpt->number);
>  }
>  
> +/* A callback for map_breakpoint_numbers that calls
> +   disable_breakpoint.  */
> +
> +static void
> +do_map_disable_breakpoint (struct breakpoint *b, void *ignore)
> +{
> +  disable_breakpoint (b);
> +}
> +
>  static void
>  disable_command (char *args, int from_tty)
>  {
> @@ -9597,7 +9667,7 @@ disable_command (char *args, int from_tty)
>        update_global_location_list (0);
>      }
>    else
> -    map_breakpoint_numbers (args, disable_breakpoint);
> +    map_breakpoint_numbers (args, do_map_disable_breakpoint, NULL);
>  }
>  
>  static void
> @@ -9654,6 +9724,15 @@ enable_breakpoint (struct breakpoint *bpt)
>    do_enable_breakpoint (bpt, bpt->disposition);
>  }
>  
> +/* A callback for map_breakpoint_numbers that calls
> +   enable_breakpoint.  */
> +
> +static void
> +do_map_enable_breakpoint (struct breakpoint *b, void *ignore)
> +{
> +  enable_breakpoint (b);
> +}
> +
>  /* The enable command enables the specified breakpoints (or all defined
>     breakpoints) so they once again become (or continue to be) effective
>     in stopping the inferior.  */
> @@ -9691,11 +9770,11 @@ enable_command (char *args, int from_tty)
>        update_global_location_list (1);
>      }
>    else
> -    map_breakpoint_numbers (args, enable_breakpoint);
> +    map_breakpoint_numbers (args, do_map_enable_breakpoint, NULL);
>  }
>  
>  static void
> -enable_once_breakpoint (struct breakpoint *bpt)
> +enable_once_breakpoint (struct breakpoint *bpt, void *ignore)
>  {
>    do_enable_breakpoint (bpt, disp_disable);
>  }
> @@ -9703,11 +9782,11 @@ enable_once_breakpoint (struct breakpoint *bpt)
>  static void
>  enable_once_command (char *args, int from_tty)
>  {
> -  map_breakpoint_numbers (args, enable_once_breakpoint);
> +  map_breakpoint_numbers (args, enable_once_breakpoint, NULL);
>  }
>  
>  static void
> -enable_delete_breakpoint (struct breakpoint *bpt)
> +enable_delete_breakpoint (struct breakpoint *bpt, void *ignore)
>  {
>    do_enable_breakpoint (bpt, disp_del);
>  }
> @@ -9715,7 +9794,7 @@ enable_delete_breakpoint (struct breakpoint *bpt)
>  static void
>  enable_delete_command (char *args, int from_tty)
>  {
> -  map_breakpoint_numbers (args, enable_delete_breakpoint);
> +  map_breakpoint_numbers (args, enable_delete_breakpoint, NULL);
>  }
>  \f
>  static void
> @@ -10138,7 +10217,7 @@ delete_trace_command (char *arg, int from_tty)
>  	}
>      }
>    else
> -    map_breakpoint_numbers (arg, delete_breakpoint);
> +    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
>  }
>  
>  /* Set passcount for tracepoint.
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 1480991..8e36f21 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1012,4 +1012,9 @@ extern struct breakpoint *get_tracepoint_by_number (char **arg, int multi_p,
>     is newly allocated; the caller should free when done with it.  */
>  extern VEC(breakpoint_p) *all_tracepoints (void);
>  
> +/* Call at the start and end of an "rbreak" command to register
> +   breakpoint numbers for a later "commands" command.  */
> +extern void start_rbreak_breakpoints (void);
> +extern void end_rbreak_breakpoints (void);
> +
>  #endif /* !defined (BREAKPOINT_H) */
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index f6105b7..557316a 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4326,19 +4326,21 @@ enable other breakpoints.
>  @table @code
>  @kindex commands
>  @kindex end@r{ (breakpoint commands)}
> -@item commands @r{[}@var{bnum}@r{]}
> +@item commands @r{[}@var{range}@dots{}@r{]}
>  @itemx @dots{} @var{command-list} @dots{}
>  @itemx end
> -Specify a list of commands for breakpoint number @var{bnum}.  The commands
> +Specify a list of commands for the given breakpoints.  The commands
>  themselves appear on the following lines.  Type a line containing just
>  @code{end} to terminate the commands.
>  
>  To remove all commands from a breakpoint, type @code{commands} and
>  follow it immediately with @code{end}; that is, give no commands.
>  
> -With no @var{bnum} argument, @code{commands} refers to the last
> -breakpoint, watchpoint, or catchpoint set (not to the breakpoint most
> -recently encountered).
> +With no argument, @code{commands} refers to the last breakpoint,
> +watchpoint, or catchpoint set (not to the breakpoint most recently
> +encountered).  If the most recent breakpoints were set with an
> +@command{rbreak} command, then the @code{commands} will apply to all
> +the breakpoints set by that @command{rbreak}.
>  @end table
>  
>  Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
> diff --git a/gdb/symtab.c b/gdb/symtab.c
> index af4e501..e9a3c0f 100644
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -3610,23 +3610,41 @@ rbreak_command_wrapper (char *regexp, int from_tty)
>    rbreak_command (regexp, from_tty);
>  }
>  
> +/* A cleanup function that calls end_rbreak_breakpoints.  */
> +
> +static void
> +do_end_rbreak_breakpoints (void *ignore)
> +{
> +  end_rbreak_breakpoints ();
> +}
> +
>  static void
>  rbreak_command (char *regexp, int from_tty)
>  {
>    struct symbol_search *ss;
>    struct symbol_search *p;
>    struct cleanup *old_chain;
> +  char *string = NULL;
> +  int len = 0;
>  
>    search_symbols (regexp, FUNCTIONS_DOMAIN, 0, (char **) NULL, &ss);
>    old_chain = make_cleanup_free_search_symbols (ss);
> +  make_cleanup (free_current_contents, &string);
>  
> +  start_rbreak_breakpoints ();
> +  make_cleanup (do_end_rbreak_breakpoints, NULL);
>    for (p = ss; p != NULL; p = p->next)
>      {
>        if (p->msymbol == NULL)
>  	{
> -	  char *string = alloca (strlen (p->symtab->filename)
> -				 + strlen (SYMBOL_LINKAGE_NAME (p->symbol))
> -				 + 4);
> +	  int newlen = (strlen (p->symtab->filename)
> +			+ strlen (SYMBOL_LINKAGE_NAME (p->symbol))
> +			+ 4);
> +	  if (newlen > len)
> +	    {
> +	      string = xrealloc (string, newlen);
> +	      len = newlen;
> +	    }
>  	  strcpy (string, p->symtab->filename);
>  	  strcat (string, ":'");
>  	  strcat (string, SYMBOL_LINKAGE_NAME (p->symbol));
> @@ -3640,8 +3658,13 @@ rbreak_command (char *regexp, int from_tty)
>  	}
>        else
>  	{
> -	  char *string = alloca (strlen (SYMBOL_LINKAGE_NAME (p->msymbol))
> -				 + 3);
> +	  int newlen = (strlen (SYMBOL_LINKAGE_NAME (p->msymbol))
> +			+ 3);
> +	  if (newlen > len)
> +	    {
> +	      string = xrealloc (string, newlen);
> +	      len = newlen;
> +	    }
>  	  strcpy (string, "'");
>  	  strcat (string, SYMBOL_LINKAGE_NAME (p->msymbol));
>  	  strcat (string, "'");
> diff --git a/gdb/testsuite/gdb.base/commands.exp b/gdb/testsuite/gdb.base/commands.exp
> index b3257aa..6514e81 100644
> --- a/gdb/testsuite/gdb.base/commands.exp
> +++ b/gdb/testsuite/gdb.base/commands.exp
> @@ -299,7 +299,7 @@ proc watchpoint_command_test {} {
>  
>      send_gdb "commands $wp_id\n"
>      gdb_expect {
> -      -re "Type commands for when breakpoint $wp_id is hit, one per line.*>" {
> +      -re "Type commands for all specified breakpoints.*>" {
>  	  pass "begin commands on watch"
>        }
>        -re "$gdb_prompt $" {fail "begin commands on watch"}
> @@ -452,7 +452,7 @@ proc bp_deleted_in_command_test {} {
>      
>      send_gdb "commands\n"
>      gdb_expect {
> -      -re "Type commands for when breakpoint .* is hit, one per line.*>" {
> +      -re "Type commands for all specified breakpoints.*>" {
>            pass "begin commands in bp_deleted_in_command_test"
>        }
>        -re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
> @@ -519,7 +519,7 @@ proc temporary_breakpoint_commands {} {
>      
>      send_gdb "commands\n"
>      gdb_expect {
> -	-re "Type commands for when breakpoint .* is hit, one per line.*>" {
> +	-re "Type commands for all specified breakpoints.*>" {
>  	    pass "begin commands in bp_deleted_in_command_test"
>  	}
>  	-re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
> diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
> index 9603fd4..3a7e1e8 100644
> --- a/gdb/testsuite/gdb.base/default.exp
> +++ b/gdb/testsuite/gdb.base/default.exp
> @@ -100,7 +100,7 @@ gdb_test "cd" "Argument required .new working directory.*" "cd"
>  gdb_test "clear" "No source file specified..*" "clear"
>  
>  #test commands
> -gdb_test "commands" "No breakpoint number 0..*" "commands"
> +gdb_test "commands" "Argument required .one or more breakpoint numbers...*" "commands"
>  
>  #test condition
>  gdb_test "condition" "Argument required .breakpoint number.*" "condition"
> 


-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-10  3:54 [2/2] RFC: let "commands" affect multiple breakpoints Tom Tromey
  2010-03-10 16:34 ` Tom Tromey
  2010-03-10 17:05 ` Pedro Alves
@ 2010-03-10 17:37 ` Eli Zaretskii
  2010-03-11 20:50   ` Tom Tromey
  2 siblings, 1 reply; 14+ messages in thread
From: Eli Zaretskii @ 2010-03-10 17:37 UTC (permalink / raw)
  To: tromey; +Cc: gdb-patches

> From: Tom Tromey <tromey@redhat.com>
> Date: Tue, 09 Mar 2010 20:54:28 -0700
> 
>  *** Changes since GDB 7.1
>  
> +* The `commands' command now accepts a range of breakpoints to modify.
> +  A plain `commands' following an `rbreak' will affect all the
> +  breakpoints set by `rbreak'.

This is okay, but maybe it will need a slight modification, see
below.

> -@item commands @r{[}@var{bnum}@r{]}
> +@item commands @r{[}@var{range}@dots{}@r{]}
>  @itemx @dots{} @var{command-list} @dots{}
>  @itemx end
> -Specify a list of commands for breakpoint number @var{bnum}.  The commands
> +Specify a list of commands for the given breakpoints.  The commands
>  themselves appear on the following lines.  Type a line containing just
>  @code{end} to terminate the commands.

You never say what is the valid syntax of RANGE.  Do I understand
correctly that RANGE could be "12-34"?  Can it also be "1 2 3 4",
i.e. a list of numbers?  What about mixing those ("1-10 25 35")?

Depending on the answers, the NEWS entry might need some clarification
or maybe just an example.

Thanks.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-10 17:37 ` Eli Zaretskii
@ 2010-03-11 20:50   ` Tom Tromey
  2010-03-12  7:53     ` Eli Zaretskii
  0 siblings, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2010-03-11 20:50 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

>> -@item commands @r{[}@var{bnum}@r{]}
>> +@item commands @r{[}@var{range}@dots{}@r{]}
>> @itemx @dots{} @var{command-list} @dots{}
>> @itemx end
>> -Specify a list of commands for breakpoint number @var{bnum}.  The commands
>> +Specify a list of commands for the given breakpoints.  The commands
>> themselves appear on the following lines.  Type a line containing just
>> @code{end} to terminate the commands.

Eli> You never say what is the valid syntax of RANGE.  Do I understand
Eli> correctly that RANGE could be "12-34"?  Can it also be "1 2 3 4",
Eli> i.e. a list of numbers?  What about mixing those ("1-10 25 35")?

Ranges are already described in the parent node, Breakpoints.
Also, none of the other places that use ranges refer to this node.

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-10 17:05 ` Pedro Alves
@ 2010-03-11 21:42   ` Tom Tromey
  2010-03-23  4:23     ` Tom Tromey
  0 siblings, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2010-03-11 21:42 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

>>>>> "Pedro" == Pedro Alves <pedro@codesourcery.com> writes:

Pedro> I'm okay with change.  I only skimmed throught the patch, but I
Pedro> was wondering if it should be generalized to not be specific to
Pedro> rbreak only, but to all cases we create more than one breakpoint
Pedro> with a single command?
[...]
Pedro> Just curious if you considered it, and decided against it.

Nope, I just didn't think of it.
I am looking into it.

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-11 20:50   ` Tom Tromey
@ 2010-03-12  7:53     ` Eli Zaretskii
  0 siblings, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2010-03-12  7:53 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> From: Tom Tromey <tromey@redhat.com>
> Cc: gdb-patches@sourceware.org
> Date: Thu, 11 Mar 2010 13:50:03 -0700
> 
> >>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> -@item commands @r{[}@var{bnum}@r{]}
> >> +@item commands @r{[}@var{range}@dots{}@r{]}
> >> @itemx @dots{} @var{command-list} @dots{}
> >> @itemx end
> >> -Specify a list of commands for breakpoint number @var{bnum}.  The commands
> >> +Specify a list of commands for the given breakpoints.  The commands
> >> themselves appear on the following lines.  Type a line containing just
> >> @code{end} to terminate the commands.
> 
> Eli> You never say what is the valid syntax of RANGE.  Do I understand
> Eli> correctly that RANGE could be "12-34"?  Can it also be "1 2 3 4",
> Eli> i.e. a list of numbers?  What about mixing those ("1-10 25 35")?
> 
> Ranges are already described in the parent node, Breakpoints.

You are right, sorry I didn't remember that.

So the patch for the manual is ready to go in.  Thanks.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-11 21:42   ` Tom Tromey
@ 2010-03-23  4:23     ` Tom Tromey
  2010-03-23 17:24       ` Eli Zaretskii
  2010-03-24 21:21       ` Tom Tromey
  0 siblings, 2 replies; 14+ messages in thread
From: Tom Tromey @ 2010-03-23  4:23 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Pedro> I'm okay with change.  I only skimmed throught the patch, but I
Pedro> was wondering if it should be generalized to not be specific to
Pedro> rbreak only, but to all cases we create more than one breakpoint
Pedro> with a single command?
Tom> [...]
Pedro> Just curious if you considered it, and decided against it.

Tom> Nope, I just didn't think of it.
Tom> I am looking into it.

Here is a replacement patch which implements this.

This needs another doc review, as I changed the text a bit relative to
the previous patch.

Tom

2010-03-12  Tom Tromey  <tromey@redhat.com>

	PR breakpoints/9352:
	* NEWS: Mention changes to `commands' and `rbreak'.
	* symtab.c (do_end_rbreak_breakpoints): New function.
	(rbreak_command): Call start_rbreak_breakpoints; arrange to call
	end_rbreak_breakpoints.
	* breakpoint.c (breakpoint_count, tracepoint_count): Now static.
	(set_breakpoint_count): Likewise.  Clear last_was_multi.
	(multi_start, multi_end, last_was_multi): New globals.
	(start_rbreak_breakpoints, end_rbreak_breakpoints): New
	functions.
	(struct commands_info): New
	(do_map_commands_command): New function.
	(commands_command_1): New function.
	(commands_command): Use it.
	(commands_from_control_command): Likewise.
	(do_delete_breakpoint): New function.
	(delete_command): Use it.
	(map_breakpoint_numbers): Add 'data' argument.  Pass to callback.
	(do_map_disable_breakpoint): New function.
	(disable_command): Use it.
	(do_map_enable_breakpoint): New function.
	(enable_command): Use it.
	(enable_once_breakpoint): Add argument.
	(enable_once_command): Update.
	(enable_delete_breakpoint): Add argument.
	(enable_delete_command): Update.
	(break_command_really): Set last_was_multi when needed.
	* breakpoint.h (start_rbreak_breakpoints, end_rbreak_breakpoints):
	Declare.

2010-03-12  Tom Tromey  <tromey@redhat.com>

	PR breakpoints/9352:
	* gdb.texinfo (Break Commands): Update.

2010-03-09  Tom Tromey  <tromey@redhat.com>

	PR breakpoints/9352:
	* gdb.base/default.exp: Update.
	* gdb.base/commands.exp: Update.

diff --git a/gdb/NEWS b/gdb/NEWS
index 64c48f6..b6ddf58 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -13,6 +13,10 @@
   16-bit word register AX that are actually portions of the 32-bit
   register EAX or 64-bit register RAX.
 
+* The `commands' command now accepts a range of breakpoints to modify.
+  A plain `commands' following an `rbreak' will affect all the
+  breakpoints set by `rbreak'.
+
 * Python scripting
 
 ** The GDB Python API now has access to symbols, symbol tables, and
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index b50c190..807916f 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -79,17 +79,15 @@
 
 static void enable_delete_command (char *, int);
 
-static void enable_delete_breakpoint (struct breakpoint *);
-
 static void enable_once_command (char *, int);
 
-static void enable_once_breakpoint (struct breakpoint *);
-
 static void disable_command (char *, int);
 
 static void enable_command (char *, int);
 
-static void map_breakpoint_numbers (char *, void (*)(struct breakpoint *));
+static void map_breakpoint_numbers (char *, void (*) (struct breakpoint *,
+						      void *),
+				    void *);
 
 static void ignore_command (char *, int);
 
@@ -146,8 +144,6 @@ static void condition_command (char *, int);
 
 static int get_number_trailer (char **, int);
 
-void set_breakpoint_count (int);
-
 typedef enum
   {
     mark_inserted,
@@ -392,11 +388,19 @@ VEC(bp_location_p) *moribund_locations = NULL;
 
 /* Number of last breakpoint made.  */
 
-int breakpoint_count;
+static int breakpoint_count;
+
+/* If the last command to create a breakpoint created multiple
+   breakpoints, this holds the start and end breakpoint numbers.  */
+static int multi_start;
+static int multi_end;
+/* True if the last breakpoint set was part of a group set with a
+   single command, e.g., "rbreak".  */
+static int last_was_multi;
 
 /* Number of last tracepoint made.  */
 
-int tracepoint_count;
+static int tracepoint_count;
 
 /* Return whether a breakpoint is an active enabled breakpoint.  */
 static int
@@ -407,13 +411,34 @@ breakpoint_enabled (struct breakpoint *b)
 
 /* Set breakpoint count to NUM.  */
 
-void
+static void
 set_breakpoint_count (int num)
 {
   breakpoint_count = num;
+  last_was_multi = 0;
   set_internalvar_integer (lookup_internalvar ("bpnum"), num);
 }
 
+/* Called at the start an "rbreak" command to record the first
+   breakpoint made.  */
+void
+start_rbreak_breakpoints (void)
+{
+  multi_start = breakpoint_count + 1;
+}
+
+/* Called at the end of an "rbreak" command to record the last
+   breakpoint made.  */
+void
+end_rbreak_breakpoints (void)
+{
+  if (breakpoint_count >= multi_start)
+    {
+      multi_end = breakpoint_count;
+      last_was_multi = 1;
+    }
+}
+
 /* Used in run_command to zero the hit count when a new run starts. */
 
 void
@@ -760,32 +785,86 @@ breakpoint_set_commands (struct breakpoint *b, struct command_line *commands)
   observer_notify_breakpoint_modified (b->number);
 }
 
+/* A structure used to pass information through
+   map_breakpoint_numbers.  */
+
+struct commands_info
+{
+  /* True if the command was typed at a tty.  */
+  int from_tty;
+  /* Non-NULL if the body of the commands are being read from this
+     already-parsed command.  */
+  struct command_line *control;
+  /* The command lines read from the user, or NULL if they have not
+     yet been read.  */
+  struct counted_command_line *cmd;
+};
+
+/* A callback for map_breakpoint_numbers that sets the commands for
+   commands_command.  */
+
 static void
-commands_command (char *arg, int from_tty)
+do_map_commands_command (struct breakpoint *b, void *data)
 {
-  struct breakpoint *b;
-  char *p;
-  int bnum;
-  struct command_line *l;
+  struct commands_info *info = data;
 
-  p = arg;
-  bnum = get_number (&p);
+  if (info->cmd == NULL)
+    {
+      struct command_line *l;
+      if (info->control != NULL)
+	l = copy_command_lines (info->control->body_list[0]);
+      else
+	l = read_command_lines (_("Type commands for all specified breakpoints"),
+				info->from_tty, 1);
+      info->cmd = alloc_counted_command_line (l);
+    }
+
+  /* If a breakpoint was on the list more than once, we don't need to
+     do anything.  */
+  if (b->commands != info->cmd)
+    {
+      incref_counted_command_line (info->cmd);
+      decref_counted_command_line (&b->commands);
+      b->commands = info->cmd;
+      breakpoints_changed ();
+      observer_notify_breakpoint_modified (b->number);
+    }
+}
 
-  if (p && *p)
-    error (_("Unexpected extra arguments following breakpoint number."));
+static void
+commands_command_1 (char *arg, int from_tty, struct command_line *control)
+{
+  struct cleanup *cleanups;
+  struct commands_info info;
 
-  ALL_BREAKPOINTS (b)
-    if (b->number == bnum)
-      {
-	char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.", 
-				 bnum);
-	struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
-	l = read_command_lines (tmpbuf, from_tty, 1);
-	do_cleanups (cleanups);
-	breakpoint_set_commands (b, l);
-	return;
+  info.from_tty = from_tty;
+  info.control = control;
+  info.cmd = NULL;
+  /* If we read command lines from the user, then `info' will hold an
+     extra reference to the commands that we must clean up.  */
+  cleanups = make_cleanup_decref_counted_command_line (&info.cmd);
+
+  if (arg == NULL || !*arg)
+    {
+      if (last_was_multi)
+	arg = xstrprintf ("%d-%d", multi_start, multi_end);
+      else if (breakpoint_count > 0)
+	arg = xstrprintf ("%d", breakpoint_count);
+      make_cleanup (xfree, arg);
     }
-  error (_("No breakpoint number %d."), bnum);
+
+  map_breakpoint_numbers (arg, do_map_commands_command, &info);
+
+  if (info.cmd == NULL)
+    error (_("No breakpoints specified."));
+
+  do_cleanups (cleanups);
+}
+
+static void
+commands_command (char *arg, int from_tty)
+{
+  commands_command_1 (arg, from_tty, NULL);
 }
 
 /* Like commands_command, but instead of reading the commands from
@@ -796,36 +875,8 @@ commands_command (char *arg, int from_tty)
 enum command_control_type
 commands_from_control_command (char *arg, struct command_line *cmd)
 {
-  struct breakpoint *b;
-  char *p;
-  int bnum;
-
-  /* An empty string for the breakpoint number means the last
-     breakpoint, but get_number expects a NULL pointer.  */
-  if (arg && !*arg)
-    p = NULL;
-  else
-    p = arg;
-  bnum = get_number (&p);
-
-  if (p && *p)
-    error (_("Unexpected extra arguments following breakpoint number."));
-
-  ALL_BREAKPOINTS (b)
-    if (b->number == bnum)
-      {
-	decref_counted_command_line (&b->commands);
-	if (cmd->body_count != 1)
-	  error (_("Invalid \"commands\" block structure."));
-	/* We need to copy the commands because if/while will free the
-	   list after it finishes execution.  */
-	b->commands
-	  = alloc_counted_command_line (copy_command_lines (cmd->body_list[0]));
-	breakpoints_changed ();
-	observer_notify_breakpoint_modified (b->number);
-	return simple_control;
-      }
-  error (_("No breakpoint number %d."), bnum);
+  commands_command_1 (arg, 0, cmd);
+  return simple_control;
 }
 
 /* Return non-zero if BL->TARGET_INFO contains valid information.  */
@@ -7031,6 +7082,7 @@ break_command_really (struct gdbarch *gdbarch,
   int not_found = 0;
   enum bptype type_wanted;
   int task = 0;
+  int first_bp_set = breakpoint_count + 1;
 
   sals.sals = NULL;
   sals.nelts = 0;
@@ -7186,8 +7238,14 @@ break_command_really (struct gdbarch *gdbarch,
     }
   
   if (sals.nelts > 1)
-    warning (_("Multiple breakpoints were set.\n"
-	       "Use the \"delete\" command to delete unwanted breakpoints."));
+    {
+      warning (_("Multiple breakpoints were set.\n"
+		 "Use the \"delete\" command to delete unwanted breakpoints."));
+      multi_start = first_bp_set;
+      multi_end = breakpoint_count;
+      last_was_multi = 1;
+    }
+
   /* That's it.  Discard the cleanups for data inserted into the
      breakpoint.  */
   discard_cleanups (bkpt_chain);
@@ -9059,6 +9117,15 @@ make_cleanup_delete_breakpoint (struct breakpoint *b)
   return make_cleanup (do_delete_breakpoint_cleanup, b);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   delete_breakpoint.  */
+
+static void
+do_delete_breakpoint (struct breakpoint *b, void *ignore)
+{
+  delete_breakpoint (b);
+}
+
 void
 delete_command (char *arg, int from_tty)
 {
@@ -9106,7 +9173,7 @@ delete_command (char *arg, int from_tty)
 	}
     }
   else
-    map_breakpoint_numbers (arg, delete_breakpoint);
+    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
 }
 
 static int
@@ -9567,7 +9634,9 @@ ignore_command (char *args, int from_tty)
    whose numbers are given in ARGS.  */
 
 static void
-map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
+map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *,
+						      void *),
+			void *data)
 {
   char *p = args;
   char *p1;
@@ -9595,9 +9664,9 @@ map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
 	      {
 		struct breakpoint *related_breakpoint = b->related_breakpoint;
 		match = 1;
-		function (b);
+		function (b, data);
 		if (related_breakpoint)
-		  function (related_breakpoint);
+		  function (related_breakpoint, data);
 		break;
 	      }
 	  if (match == 0)
@@ -9673,6 +9742,15 @@ disable_breakpoint (struct breakpoint *bpt)
   observer_notify_breakpoint_modified (bpt->number);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   disable_breakpoint.  */
+
+static void
+do_map_disable_breakpoint (struct breakpoint *b, void *ignore)
+{
+  disable_breakpoint (b);
+}
+
 static void
 disable_command (char *args, int from_tty)
 {
@@ -9706,7 +9784,7 @@ disable_command (char *args, int from_tty)
       update_global_location_list (0);
     }
   else
-    map_breakpoint_numbers (args, disable_breakpoint);
+    map_breakpoint_numbers (args, do_map_disable_breakpoint, NULL);
 }
 
 static void
@@ -9763,6 +9841,15 @@ enable_breakpoint (struct breakpoint *bpt)
   do_enable_breakpoint (bpt, bpt->disposition);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   enable_breakpoint.  */
+
+static void
+do_map_enable_breakpoint (struct breakpoint *b, void *ignore)
+{
+  enable_breakpoint (b);
+}
+
 /* The enable command enables the specified breakpoints (or all defined
    breakpoints) so they once again become (or continue to be) effective
    in stopping the inferior.  */
@@ -9800,11 +9887,11 @@ enable_command (char *args, int from_tty)
       update_global_location_list (1);
     }
   else
-    map_breakpoint_numbers (args, enable_breakpoint);
+    map_breakpoint_numbers (args, do_map_enable_breakpoint, NULL);
 }
 
 static void
-enable_once_breakpoint (struct breakpoint *bpt)
+enable_once_breakpoint (struct breakpoint *bpt, void *ignore)
 {
   do_enable_breakpoint (bpt, disp_disable);
 }
@@ -9812,11 +9899,11 @@ enable_once_breakpoint (struct breakpoint *bpt)
 static void
 enable_once_command (char *args, int from_tty)
 {
-  map_breakpoint_numbers (args, enable_once_breakpoint);
+  map_breakpoint_numbers (args, enable_once_breakpoint, NULL);
 }
 
 static void
-enable_delete_breakpoint (struct breakpoint *bpt)
+enable_delete_breakpoint (struct breakpoint *bpt, void *ignore)
 {
   do_enable_breakpoint (bpt, disp_del);
 }
@@ -9824,7 +9911,7 @@ enable_delete_breakpoint (struct breakpoint *bpt)
 static void
 enable_delete_command (char *args, int from_tty)
 {
-  map_breakpoint_numbers (args, enable_delete_breakpoint);
+  map_breakpoint_numbers (args, enable_delete_breakpoint, NULL);
 }
 \f
 static void
@@ -10247,7 +10334,7 @@ delete_trace_command (char *arg, int from_tty)
 	}
     }
   else
-    map_breakpoint_numbers (arg, delete_breakpoint);
+    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
 }
 
 /* Set passcount for tracepoint.
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 5db2df6..d1301b6 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1019,4 +1019,9 @@ extern struct breakpoint *get_tracepoint_by_number (char **arg, int multi_p,
    is newly allocated; the caller should free when done with it.  */
 extern VEC(breakpoint_p) *all_tracepoints (void);
 
+/* Call at the start and end of an "rbreak" command to register
+   breakpoint numbers for a later "commands" command.  */
+extern void start_rbreak_breakpoints (void);
+extern void end_rbreak_breakpoints (void);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a1f3a78..dd1a53f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4328,19 +4328,23 @@ enable other breakpoints.
 @table @code
 @kindex commands
 @kindex end@r{ (breakpoint commands)}
-@item commands @r{[}@var{bnum}@r{]}
+@item commands @r{[}@var{range}@dots{}@r{]}
 @itemx @dots{} @var{command-list} @dots{}
 @itemx end
-Specify a list of commands for breakpoint number @var{bnum}.  The commands
+Specify a list of commands for the given breakpoints.  The commands
 themselves appear on the following lines.  Type a line containing just
 @code{end} to terminate the commands.
 
 To remove all commands from a breakpoint, type @code{commands} and
 follow it immediately with @code{end}; that is, give no commands.
 
-With no @var{bnum} argument, @code{commands} refers to the last
-breakpoint, watchpoint, or catchpoint set (not to the breakpoint most
-recently encountered).
+With no argument, @code{commands} refers to the last breakpoint,
+watchpoint, or catchpoint set (not to the breakpoint most recently
+encountered).  If the most recent breakpoints were set with a single
+command, then the @code{commands} will apply to all the breakpoints
+set by that command.  This applies to breakpoints set by
+@code{rbreak}, and also breakpoints set with @code{break} that have
+multiple locations.
 @end table
 
 Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
diff --git a/gdb/symtab.c b/gdb/symtab.c
index aa0aae6..bec790b 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3155,23 +3155,41 @@ rbreak_command_wrapper (char *regexp, int from_tty)
   rbreak_command (regexp, from_tty);
 }
 
+/* A cleanup function that calls end_rbreak_breakpoints.  */
+
+static void
+do_end_rbreak_breakpoints (void *ignore)
+{
+  end_rbreak_breakpoints ();
+}
+
 static void
 rbreak_command (char *regexp, int from_tty)
 {
   struct symbol_search *ss;
   struct symbol_search *p;
   struct cleanup *old_chain;
+  char *string = NULL;
+  int len = 0;
 
   search_symbols (regexp, FUNCTIONS_DOMAIN, 0, (char **) NULL, &ss);
   old_chain = make_cleanup_free_search_symbols (ss);
+  make_cleanup (free_current_contents, &string);
 
+  start_rbreak_breakpoints ();
+  make_cleanup (do_end_rbreak_breakpoints, NULL);
   for (p = ss; p != NULL; p = p->next)
     {
       if (p->msymbol == NULL)
 	{
-	  char *string = alloca (strlen (p->symtab->filename)
-				 + strlen (SYMBOL_LINKAGE_NAME (p->symbol))
-				 + 4);
+	  int newlen = (strlen (p->symtab->filename)
+			+ strlen (SYMBOL_LINKAGE_NAME (p->symbol))
+			+ 4);
+	  if (newlen > len)
+	    {
+	      string = xrealloc (string, newlen);
+	      len = newlen;
+	    }
 	  strcpy (string, p->symtab->filename);
 	  strcat (string, ":'");
 	  strcat (string, SYMBOL_LINKAGE_NAME (p->symbol));
@@ -3185,8 +3203,13 @@ rbreak_command (char *regexp, int from_tty)
 	}
       else
 	{
-	  char *string = alloca (strlen (SYMBOL_LINKAGE_NAME (p->msymbol))
-				 + 3);
+	  int newlen = (strlen (SYMBOL_LINKAGE_NAME (p->msymbol))
+			+ 3);
+	  if (newlen > len)
+	    {
+	      string = xrealloc (string, newlen);
+	      len = newlen;
+	    }
 	  strcpy (string, "'");
 	  strcat (string, SYMBOL_LINKAGE_NAME (p->msymbol));
 	  strcat (string, "'");
diff --git a/gdb/testsuite/gdb.base/commands.exp b/gdb/testsuite/gdb.base/commands.exp
index b3257aa..6514e81 100644
--- a/gdb/testsuite/gdb.base/commands.exp
+++ b/gdb/testsuite/gdb.base/commands.exp
@@ -299,7 +299,7 @@ proc watchpoint_command_test {} {
 
     send_gdb "commands $wp_id\n"
     gdb_expect {
-      -re "Type commands for when breakpoint $wp_id is hit, one per line.*>" {
+      -re "Type commands for all specified breakpoints.*>" {
 	  pass "begin commands on watch"
       }
       -re "$gdb_prompt $" {fail "begin commands on watch"}
@@ -452,7 +452,7 @@ proc bp_deleted_in_command_test {} {
     
     send_gdb "commands\n"
     gdb_expect {
-      -re "Type commands for when breakpoint .* is hit, one per line.*>" {
+      -re "Type commands for all specified breakpoints.*>" {
           pass "begin commands in bp_deleted_in_command_test"
       }
       -re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
@@ -519,7 +519,7 @@ proc temporary_breakpoint_commands {} {
     
     send_gdb "commands\n"
     gdb_expect {
-	-re "Type commands for when breakpoint .* is hit, one per line.*>" {
+	-re "Type commands for all specified breakpoints.*>" {
 	    pass "begin commands in bp_deleted_in_command_test"
 	}
 	-re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index 9603fd4..3a7e1e8 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -100,7 +100,7 @@ gdb_test "cd" "Argument required .new working directory.*" "cd"
 gdb_test "clear" "No source file specified..*" "clear"
 
 #test commands
-gdb_test "commands" "No breakpoint number 0..*" "commands"
+gdb_test "commands" "Argument required .one or more breakpoint numbers...*" "commands"
 
 #test condition
 gdb_test "condition" "Argument required .breakpoint number.*" "condition"
-- 
1.6.6.1

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-23  4:23     ` Tom Tromey
@ 2010-03-23 17:24       ` Eli Zaretskii
  2010-03-24 21:21       ` Tom Tromey
  1 sibling, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2010-03-23 17:24 UTC (permalink / raw)
  To: tromey; +Cc: pedro, gdb-patches

> From: Tom Tromey <tromey@redhat.com>
> Cc: gdb-patches@sourceware.org
> Date: Mon, 22 Mar 2010 22:23:25 -0600
> 
> 2010-03-12  Tom Tromey  <tromey@redhat.com>
> 
> 	PR breakpoints/9352:
> 	* NEWS: Mention changes to `commands' and `rbreak'.
> 
> 2010-03-12  Tom Tromey  <tromey@redhat.com>
> 
> 	PR breakpoints/9352:
> 	* gdb.texinfo (Break Commands): Update.

These two parts are okay.  Thanks.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-23  4:23     ` Tom Tromey
  2010-03-23 17:24       ` Eli Zaretskii
@ 2010-03-24 21:21       ` Tom Tromey
  2010-03-25 17:09         ` Pedro Alves
  1 sibling, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2010-03-24 21:21 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Tom> Here is a replacement patch which implements this.

I'm checking in the appended.  This is the revised patch, rebased on top
of Volodya's patches.

Tom

2010-03-24  Tom Tromey  <tromey@redhat.com>

	PR breakpoints/9352:
	* NEWS: Mention changes to `commands' and `rbreak'.
	* symtab.c (do_end_rbreak_breakpoints): New function.
	(rbreak_command): Call start_rbreak_breakpoints; arrange to call
	end_rbreak_breakpoints.
	* breakpoint.c (breakpoint_count, tracepoint_count): Now static.
	(set_breakpoint_count): Likewise.  Clear last_was_multi.
	(multi_start, multi_end, last_was_multi): New globals.
	(start_rbreak_breakpoints, end_rbreak_breakpoints): New
	functions.
	(struct commands_info): New
	(do_map_commands_command): New function.
	(commands_command_1): New function.
	(commands_command): Use it.
	(commands_from_control_command): Likewise.
	(do_delete_breakpoint): New function.
	(delete_command): Use it.
	(map_breakpoint_numbers): Add 'data' argument.  Pass to callback.
	(do_map_disable_breakpoint): New function.
	(disable_command): Use it.
	(do_map_enable_breakpoint): New function.
	(enable_command): Use it.
	(enable_once_breakpoint): Add argument.
	(enable_once_command): Update.
	(enable_delete_breakpoint): Add argument.
	(enable_delete_command): Update.
	(break_command_really): Set last_was_multi when needed.
	(check_tracepoint_command): Fix formatting.
	(validate_commands_for_breakpoint): New function.
	(breakpoint_set_commands): Use it.
	(tracepoint_save_command): Update.
	* breakpoint.h (start_rbreak_breakpoints, end_rbreak_breakpoints):
	Declare.

2010-03-24  Tom Tromey  <tromey@redhat.com>

	PR breakpoints/9352:
	* gdb.texinfo (Break Commands): Update.

2010-03-24  Tom Tromey  <tromey@redhat.com>

	PR breakpoints/9352:
	* gdb.base/default.exp: Update.
	* gdb.base/commands.exp: Update.
	* gdb.cp/extern-c.exp: Test setting commands on multiple
	breakpoints at once.

Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.364
diff -u -r1.364 NEWS
--- NEWS	23 Mar 2010 21:32:26 -0000	1.364
+++ NEWS	24 Mar 2010 21:19:41 -0000
@@ -13,6 +13,10 @@
   16-bit word register AX that are actually portions of the 32-bit
   register EAX or 64-bit register RAX.
 
+* The `commands' command now accepts a range of breakpoints to modify.
+  A plain `commands' following an `rbreak' will affect all the
+  breakpoints set by `rbreak'.
+
 * Python scripting
 
 ** The GDB Python API now has access to symbols, symbol tables, and
Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.466
diff -u -r1.466 breakpoint.c
--- breakpoint.c	24 Mar 2010 21:12:18 -0000	1.466
+++ breakpoint.c	24 Mar 2010 21:19:41 -0000
@@ -79,17 +79,15 @@
 
 static void enable_delete_command (char *, int);
 
-static void enable_delete_breakpoint (struct breakpoint *);
-
 static void enable_once_command (char *, int);
 
-static void enable_once_breakpoint (struct breakpoint *);
-
 static void disable_command (char *, int);
 
 static void enable_command (char *, int);
 
-static void map_breakpoint_numbers (char *, void (*)(struct breakpoint *));
+static void map_breakpoint_numbers (char *, void (*) (struct breakpoint *,
+						      void *),
+				    void *);
 
 static void ignore_command (char *, int);
 
@@ -146,8 +144,6 @@
 
 static int get_number_trailer (char **, int);
 
-void set_breakpoint_count (int);
-
 typedef enum
   {
     mark_inserted,
@@ -392,11 +388,19 @@
 
 /* Number of last breakpoint made.  */
 
-int breakpoint_count;
+static int breakpoint_count;
+
+/* If the last command to create a breakpoint created multiple
+   breakpoints, this holds the start and end breakpoint numbers.  */
+static int multi_start;
+static int multi_end;
+/* True if the last breakpoint set was part of a group set with a
+   single command, e.g., "rbreak".  */
+static int last_was_multi;
 
 /* Number of last tracepoint made.  */
 
-int tracepoint_count;
+static int tracepoint_count;
 
 /* Return whether a breakpoint is an active enabled breakpoint.  */
 static int
@@ -407,13 +411,34 @@
 
 /* Set breakpoint count to NUM.  */
 
-void
+static void
 set_breakpoint_count (int num)
 {
   breakpoint_count = num;
+  last_was_multi = 0;
   set_internalvar_integer (lookup_internalvar ("bpnum"), num);
 }
 
+/* Called at the start an "rbreak" command to record the first
+   breakpoint made.  */
+void
+start_rbreak_breakpoints (void)
+{
+  multi_start = breakpoint_count + 1;
+}
+
+/* Called at the end of an "rbreak" command to record the last
+   breakpoint made.  */
+void
+end_rbreak_breakpoints (void)
+{
+  if (breakpoint_count >= multi_start)
+    {
+      multi_end = breakpoint_count;
+      last_was_multi = 1;
+    }
+}
+
 /* Used in run_command to zero the hit count when a new run starts. */
 
 void
@@ -792,12 +817,13 @@
     }
 }
 
-/* Set the command list of B to COMMANDS.  If breakpoint is tracepoint,
-   validate that only allowed commands are included.
-*/
+/* A helper function that validsates that COMMANDS are valid for a
+   breakpoint.  This function will throw an exception if a problem is
+   found.  */
 
-void
-breakpoint_set_commands (struct breakpoint *b, struct command_line *commands)
+static void
+validate_commands_for_breakpoint (struct breakpoint *b,
+				  struct command_line *commands)
 {
   if (breakpoint_is_tracepoint (b))
     {
@@ -839,6 +865,16 @@
     {
       check_no_tracepoint_commands (commands);
     }
+}
+
+/* Set the command list of B to COMMANDS.  If breakpoint is tracepoint,
+   validate that only allowed commands are included.
+*/
+
+void
+breakpoint_set_commands (struct breakpoint *b, struct command_line *commands)
+{
+  validate_commands_for_breakpoint (b, commands);
 
   decref_counted_command_line (&b->commands);
   b->commands = alloc_counted_command_line (commands);
@@ -846,43 +882,100 @@
   observer_notify_breakpoint_modified (b->number);
 }
 
-void check_tracepoint_command (char *line, void *closure)
+void
+check_tracepoint_command (char *line, void *closure)
 {
   struct breakpoint *b = closure;
   validate_actionline (&line, b);
 }
 
+/* A structure used to pass information through
+   map_breakpoint_numbers.  */
+
+struct commands_info
+{
+  /* True if the command was typed at a tty.  */
+  int from_tty;
+  /* Non-NULL if the body of the commands are being read from this
+     already-parsed command.  */
+  struct command_line *control;
+  /* The command lines read from the user, or NULL if they have not
+     yet been read.  */
+  struct counted_command_line *cmd;
+};
+
+/* A callback for map_breakpoint_numbers that sets the commands for
+   commands_command.  */
+
 static void
-commands_command (char *arg, int from_tty)
+do_map_commands_command (struct breakpoint *b, void *data)
 {
-  struct breakpoint *b;
-  char *p;
-  int bnum;
-  struct command_line *l;
+  struct commands_info *info = data;
 
-  p = arg;
-  bnum = get_number (&p);
+  if (info->cmd == NULL)
+    {
+      struct command_line *l;
 
-  if (p && *p)
-    error (_("Unexpected extra arguments following breakpoint number."));
+      if (info->control != NULL)
+	l = copy_command_lines (info->control->body_list[0]);
+      else
 
-  ALL_BREAKPOINTS (b)
-    if (b->number == bnum)
-      {
-	char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.", 
-				 bnum);
-	struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
-
-	if (breakpoint_is_tracepoint (b))
-	  l = read_command_lines (tmpbuf, from_tty, 1,
-				  check_tracepoint_command, b);
-	else
-	  l = read_command_lines (tmpbuf, from_tty, 1, 0, 0);
-	do_cleanups (cleanups);
-	breakpoint_set_commands (b, l);
-	return;
+	l = read_command_lines (_("Type commands for all specified breakpoints"),
+				info->from_tty, 1,
+				(breakpoint_is_tracepoint (b)
+				 ? check_tracepoint_command : 0),
+				b);
+
+      info->cmd = alloc_counted_command_line (l);
+    }
+
+  /* If a breakpoint was on the list more than once, we don't need to
+     do anything.  */
+  if (b->commands != info->cmd)
+    {
+      validate_commands_for_breakpoint (b, info->cmd->commands);
+      incref_counted_command_line (info->cmd);
+      decref_counted_command_line (&b->commands);
+      b->commands = info->cmd;
+      breakpoints_changed ();
+      observer_notify_breakpoint_modified (b->number);
     }
-  error (_("No breakpoint number %d."), bnum);
+}
+
+static void
+commands_command_1 (char *arg, int from_tty, struct command_line *control)
+{
+  struct cleanup *cleanups;
+  struct commands_info info;
+
+  info.from_tty = from_tty;
+  info.control = control;
+  info.cmd = NULL;
+  /* If we read command lines from the user, then `info' will hold an
+     extra reference to the commands that we must clean up.  */
+  cleanups = make_cleanup_decref_counted_command_line (&info.cmd);
+
+  if (arg == NULL || !*arg)
+    {
+      if (last_was_multi)
+	arg = xstrprintf ("%d-%d", multi_start, multi_end);
+      else if (breakpoint_count > 0)
+	arg = xstrprintf ("%d", breakpoint_count);
+      make_cleanup (xfree, arg);
+    }
+
+  map_breakpoint_numbers (arg, do_map_commands_command, &info);
+
+  if (info.cmd == NULL)
+    error (_("No breakpoints specified."));
+
+  do_cleanups (cleanups);
+}
+
+static void
+commands_command (char *arg, int from_tty)
+{
+  commands_command_1 (arg, from_tty, NULL);
 }
 
 /* Like commands_command, but instead of reading the commands from
@@ -893,36 +986,8 @@
 enum command_control_type
 commands_from_control_command (char *arg, struct command_line *cmd)
 {
-  struct breakpoint *b;
-  char *p;
-  int bnum;
-
-  /* An empty string for the breakpoint number means the last
-     breakpoint, but get_number expects a NULL pointer.  */
-  if (arg && !*arg)
-    p = NULL;
-  else
-    p = arg;
-  bnum = get_number (&p);
-
-  if (p && *p)
-    error (_("Unexpected extra arguments following breakpoint number."));
-
-  ALL_BREAKPOINTS (b)
-    if (b->number == bnum)
-      {
-	decref_counted_command_line (&b->commands);
-	if (cmd->body_count != 1)
-	  error (_("Invalid \"commands\" block structure."));
-	/* We need to copy the commands because if/while will free the
-	   list after it finishes execution.  */
-	b->commands
-	  = alloc_counted_command_line (copy_command_lines (cmd->body_list[0]));
-	breakpoints_changed ();
-	observer_notify_breakpoint_modified (b->number);
-	return simple_control;
-      }
-  error (_("No breakpoint number %d."), bnum);
+  commands_command_1 (arg, 0, cmd);
+  return simple_control;
 }
 
 /* Return non-zero if BL->TARGET_INFO contains valid information.  */
@@ -7111,6 +7176,7 @@
   int not_found = 0;
   enum bptype type_wanted;
   int task = 0;
+  int first_bp_set = breakpoint_count + 1;
 
   sals.sals = NULL;
   sals.nelts = 0;
@@ -7267,8 +7333,14 @@
     }
   
   if (sals.nelts > 1)
-    warning (_("Multiple breakpoints were set.\n"
-	       "Use the \"delete\" command to delete unwanted breakpoints."));
+    {
+      warning (_("Multiple breakpoints were set.\n"
+		 "Use the \"delete\" command to delete unwanted breakpoints."));
+      multi_start = first_bp_set;
+      multi_end = breakpoint_count;
+      last_was_multi = 1;
+    }
+
   /* That's it.  Discard the cleanups for data inserted into the
      breakpoint.  */
   discard_cleanups (bkpt_chain);
@@ -9124,6 +9196,15 @@
   return make_cleanup (do_delete_breakpoint_cleanup, b);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   delete_breakpoint.  */
+
+static void
+do_delete_breakpoint (struct breakpoint *b, void *ignore)
+{
+  delete_breakpoint (b);
+}
+
 void
 delete_command (char *arg, int from_tty)
 {
@@ -9171,7 +9252,7 @@
 	}
     }
   else
-    map_breakpoint_numbers (arg, delete_breakpoint);
+    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
 }
 
 static int
@@ -9632,7 +9713,9 @@
    whose numbers are given in ARGS.  */
 
 static void
-map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
+map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *,
+						      void *),
+			void *data)
 {
   char *p = args;
   char *p1;
@@ -9660,9 +9743,9 @@
 	      {
 		struct breakpoint *related_breakpoint = b->related_breakpoint;
 		match = 1;
-		function (b);
+		function (b, data);
 		if (related_breakpoint)
-		  function (related_breakpoint);
+		  function (related_breakpoint, data);
 		break;
 	      }
 	  if (match == 0)
@@ -9738,6 +9821,15 @@
   observer_notify_breakpoint_modified (bpt->number);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   disable_breakpoint.  */
+
+static void
+do_map_disable_breakpoint (struct breakpoint *b, void *ignore)
+{
+  disable_breakpoint (b);
+}
+
 static void
 disable_command (char *args, int from_tty)
 {
@@ -9771,7 +9863,7 @@
       update_global_location_list (0);
     }
   else
-    map_breakpoint_numbers (args, disable_breakpoint);
+    map_breakpoint_numbers (args, do_map_disable_breakpoint, NULL);
 }
 
 static void
@@ -9828,6 +9920,15 @@
   do_enable_breakpoint (bpt, bpt->disposition);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   enable_breakpoint.  */
+
+static void
+do_map_enable_breakpoint (struct breakpoint *b, void *ignore)
+{
+  enable_breakpoint (b);
+}
+
 /* The enable command enables the specified breakpoints (or all defined
    breakpoints) so they once again become (or continue to be) effective
    in stopping the inferior.  */
@@ -9865,11 +9966,11 @@
       update_global_location_list (1);
     }
   else
-    map_breakpoint_numbers (args, enable_breakpoint);
+    map_breakpoint_numbers (args, do_map_enable_breakpoint, NULL);
 }
 
 static void
-enable_once_breakpoint (struct breakpoint *bpt)
+enable_once_breakpoint (struct breakpoint *bpt, void *ignore)
 {
   do_enable_breakpoint (bpt, disp_disable);
 }
@@ -9877,11 +9978,11 @@
 static void
 enable_once_command (char *args, int from_tty)
 {
-  map_breakpoint_numbers (args, enable_once_breakpoint);
+  map_breakpoint_numbers (args, enable_once_breakpoint, NULL);
 }
 
 static void
-enable_delete_breakpoint (struct breakpoint *bpt)
+enable_delete_breakpoint (struct breakpoint *bpt, void *ignore)
 {
   do_enable_breakpoint (bpt, disp_del);
 }
@@ -9889,7 +9990,7 @@
 static void
 enable_delete_command (char *args, int from_tty)
 {
-  map_breakpoint_numbers (args, enable_delete_breakpoint);
+  map_breakpoint_numbers (args, enable_delete_breakpoint, NULL);
 }
 \f
 static void
@@ -10312,7 +10413,7 @@
 	}
     }
   else
-    map_breakpoint_numbers (arg, delete_breakpoint);
+    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
 }
 
 /* Set passcount for tracepoint.
Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.111
diff -u -r1.111 breakpoint.h
--- breakpoint.h	24 Mar 2010 21:12:18 -0000	1.111
+++ breakpoint.h	24 Mar 2010 21:19:41 -0000
@@ -1025,4 +1025,9 @@
    that each command is suitable for tracepoint command list.  */
 extern void check_tracepoint_command (char *line, void *closure);
 
+/* Call at the start and end of an "rbreak" command to register
+   breakpoint numbers for a later "commands" command.  */
+extern void start_rbreak_breakpoints (void);
+extern void end_rbreak_breakpoints (void);
+
 #endif /* !defined (BREAKPOINT_H) */
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.228
diff -u -r1.228 symtab.c
--- symtab.c	24 Mar 2010 21:06:31 -0000	1.228
+++ symtab.c	24 Mar 2010 21:19:43 -0000
@@ -3170,23 +3170,41 @@
   rbreak_command (regexp, from_tty);
 }
 
+/* A cleanup function that calls end_rbreak_breakpoints.  */
+
+static void
+do_end_rbreak_breakpoints (void *ignore)
+{
+  end_rbreak_breakpoints ();
+}
+
 static void
 rbreak_command (char *regexp, int from_tty)
 {
   struct symbol_search *ss;
   struct symbol_search *p;
   struct cleanup *old_chain;
+  char *string = NULL;
+  int len = 0;
 
   search_symbols (regexp, FUNCTIONS_DOMAIN, 0, (char **) NULL, &ss);
   old_chain = make_cleanup_free_search_symbols (ss);
+  make_cleanup (free_current_contents, &string);
 
+  start_rbreak_breakpoints ();
+  make_cleanup (do_end_rbreak_breakpoints, NULL);
   for (p = ss; p != NULL; p = p->next)
     {
       if (p->msymbol == NULL)
 	{
-	  char *string = alloca (strlen (p->symtab->filename)
-				 + strlen (SYMBOL_LINKAGE_NAME (p->symbol))
-				 + 4);
+	  int newlen = (strlen (p->symtab->filename)
+			+ strlen (SYMBOL_LINKAGE_NAME (p->symbol))
+			+ 4);
+	  if (newlen > len)
+	    {
+	      string = xrealloc (string, newlen);
+	      len = newlen;
+	    }
 	  strcpy (string, p->symtab->filename);
 	  strcat (string, ":'");
 	  strcat (string, SYMBOL_LINKAGE_NAME (p->symbol));
@@ -3200,8 +3218,13 @@
 	}
       else
 	{
-	  char *string = alloca (strlen (SYMBOL_LINKAGE_NAME (p->msymbol))
-				 + 3);
+	  int newlen = (strlen (SYMBOL_LINKAGE_NAME (p->msymbol))
+			+ 3);
+	  if (newlen > len)
+	    {
+	      string = xrealloc (string, newlen);
+	      len = newlen;
+	    }
 	  strcpy (string, "'");
 	  strcat (string, SYMBOL_LINKAGE_NAME (p->msymbol));
 	  strcat (string, "'");
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.682
diff -u -r1.682 gdb.texinfo
--- doc/gdb.texinfo	23 Mar 2010 22:10:08 -0000	1.682
+++ doc/gdb.texinfo	24 Mar 2010 21:19:47 -0000
@@ -4328,19 +4328,23 @@
 @table @code
 @kindex commands
 @kindex end@r{ (breakpoint commands)}
-@item commands @r{[}@var{bnum}@r{]}
+@item commands @r{[}@var{range}@dots{}@r{]}
 @itemx @dots{} @var{command-list} @dots{}
 @itemx end
-Specify a list of commands for breakpoint number @var{bnum}.  The commands
+Specify a list of commands for the given breakpoints.  The commands
 themselves appear on the following lines.  Type a line containing just
 @code{end} to terminate the commands.
 
 To remove all commands from a breakpoint, type @code{commands} and
 follow it immediately with @code{end}; that is, give no commands.
 
-With no @var{bnum} argument, @code{commands} refers to the last
-breakpoint, watchpoint, or catchpoint set (not to the breakpoint most
-recently encountered).
+With no argument, @code{commands} refers to the last breakpoint,
+watchpoint, or catchpoint set (not to the breakpoint most recently
+encountered).  If the most recent breakpoints were set with a single
+command, then the @code{commands} will apply to all the breakpoints
+set by that command.  This applies to breakpoints set by
+@code{rbreak}, and also breakpoints set with @code{break} that have
+multiple locations.
 @end table
 
 Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
Index: testsuite/gdb.base/commands.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/commands.exp,v
retrieving revision 1.31
diff -u -r1.31 commands.exp
--- testsuite/gdb.base/commands.exp	12 Mar 2010 19:17:01 -0000	1.31
+++ testsuite/gdb.base/commands.exp	24 Mar 2010 21:19:56 -0000
@@ -299,7 +299,7 @@
 
     send_gdb "commands $wp_id\n"
     gdb_expect {
-      -re "Type commands for when breakpoint $wp_id is hit, one per line.*>" {
+      -re "Type commands for all specified breakpoints.*>" {
 	  pass "begin commands on watch"
       }
       -re "$gdb_prompt $" {fail "begin commands on watch"}
@@ -452,7 +452,7 @@
     
     send_gdb "commands\n"
     gdb_expect {
-      -re "Type commands for when breakpoint .* is hit, one per line.*>" {
+      -re "Type commands for all specified breakpoints.*>" {
           pass "begin commands in bp_deleted_in_command_test"
       }
       -re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
@@ -519,7 +519,7 @@
     
     send_gdb "commands\n"
     gdb_expect {
-	-re "Type commands for when breakpoint .* is hit, one per line.*>" {
+	-re "Type commands for all specified breakpoints.*>" {
 	    pass "begin commands in bp_deleted_in_command_test"
 	}
 	-re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
Index: testsuite/gdb.base/default.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/default.exp,v
retrieving revision 1.35
diff -u -r1.35 default.exp
--- testsuite/gdb.base/default.exp	18 Mar 2010 13:21:40 -0000	1.35
+++ testsuite/gdb.base/default.exp	24 Mar 2010 21:19:56 -0000
@@ -100,7 +100,7 @@
 gdb_test "clear" "No source file specified..*" "clear"
 
 #test commands
-gdb_test "commands" "No breakpoint number 0..*" "commands"
+gdb_test "commands" "Argument required .one or more breakpoint numbers...*" "commands"
 
 #test condition
 gdb_test "condition" "Argument required .breakpoint number.*" "condition"
Index: testsuite/gdb.cp/extern-c.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/extern-c.exp,v
retrieving revision 1.2
diff -u -r1.2 extern-c.exp
--- testsuite/gdb.cp/extern-c.exp	1 Jan 2010 07:32:01 -0000	1.2
+++ testsuite/gdb.cp/extern-c.exp	24 Mar 2010 21:19:56 -0000
@@ -40,7 +40,26 @@
 }
 gdb_continue_to_breakpoint "c_func" ".*c_func.*"
 
+gdb_test "set \$counter = 0" "" "initialize counter"
+
 gdb_test "rbreak c_funcs" \
     "Breakpoint.* at .*c_funcs_1.*Breakpoint.* at .*c_funcs_2.*"
+
+# Test that "commands" without an argument puts commands on both
+# breakpoints.
+gdb_test_multiple "commands" "set commands on multiple breakpoints" {
+  -re "Type commands for all specified breakpoints\r\nEnd with a line saying just \"end\".\r\n>$" {
+    gdb_test_multiple "set \$counter = \$counter + 1\nend" \
+      "command details for multiple breakpoints" {
+	-re "$gdb_prompt $" {
+	  pass "command details for multiple breakpoints"
+	}
+      }
+    pass "set commands on multiple breakpoints"
+  }
+}
+
 gdb_continue_to_breakpoint "c_funcs_1" ".*c_funcs_1.*"
+gdb_test "print \$counter" " = 1" "verify counter at first breakpoint"
 gdb_continue_to_breakpoint "c_funcs_2" ".*c_funcs_2.*"
+gdb_test "print \$counter" " = 2" "verify counter at second breakpoint"

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-24 21:21       ` Tom Tromey
@ 2010-03-25 17:09         ` Pedro Alves
  2010-03-30 20:42           ` Tom Tromey
  0 siblings, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2010-03-25 17:09 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On Wednesday 24 March 2010 21:21:08, Tom Tromey wrote:
> I'm checking in the appended.  This is the revised patch, rebased on top
> of Volodya's patches.

Thanks.

<In an earlier email, Tom said:>

> I do have a question though.  With this change, gdb prints somewhat less
> nice text for "commands":
> 
> Tom> +  l = read_command_lines (_("Type commands for all specified breakpoints"),
> Tom> +                          info->from_tty, 1);
> 
> Tom> -  char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.", 
> Tom> -                           bnum);
> 
> Any suggestions for something better here?

I have a suggestion for this, in form of a patch.  How
about we just print the breakpoint range?  I find this:

 (top-gdb) rbreak main
 ...
 ...
 (top-gdb) commands
 Type commands for breakpoint(s) 3-80, one per line.
 End with a line saying just "end".
 >

nicer than:

 (top-gdb) commands
 Type commands for all specified breakpoints
 End with a line saying just "end".
 >

as in the latter case, I didn't specify any breakpoints, so
"specified breakpoints" sounds vague, and doesn't quickly
imply that it will create commands for all previously created
breakpoints.

> 	* NEWS: Mention changes to `commands' and `rbreak'.
> 	* gdb.texinfo (Break Commands): Update.

I'm also suggesting to adjusting these to better explain that
this applies when "break" (or similars) creates more than one
breakpoint.  That is different to creating a breakpoint with
multiple locations ("multiple locations" are described both
in the manual and in NEWS); in the multiple locations case,
"commands" already applied to all locations.  I'm adding
a cross reference to where the case where multiple breakpoints
are created is described; that section has a nice example.

WDYT?

-- 
Pedro Alves

2010-03-25  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* breakpoint.c (multi_start, multi_end, last_was_multi): Delete.
	(prev_breakpoint_count): New.
	(set_breakpoint_count): Adjust.
	(rbreak_start_breakpoint_count): New.
	(start_rbreak_breakpoints): Adjust.
	(end_rbreak_breakpoints): Adjust.
	(struct commands_info) <arg>: New field.
	(do_map_commands_command): Tweak output to include breakpoint spec
	range.
	(commands_command_1): Adjust.  Avoid setting an xfree cleanup if
	ARG was empty on entry.  Set INFO's arg.
	(create_breakpoint): Adjust.

	* NEWS: Clarify `commands' changes.

	gdb/doc/
	* gdb.texinfo (Break Commands): Clarify `commands' changes, and
	add cross reference.

	gdb/testsuite/
	* gdb.base/commands.exp: Adjust.
	* gdb.cp/extern-c.exp: Adjust.

---
 gdb/NEWS                            |    7 ++-
 gdb/breakpoint.c                    |   72 +++++++++++++++++++++++-------------
 gdb/doc/gdb.texinfo                 |    5 +-
 gdb/testsuite/gdb.base/commands.exp |    6 +--
 gdb/testsuite/gdb.cp/extern-c.exp   |    2 -
 5 files changed, 58 insertions(+), 34 deletions(-)

Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2010-03-25 14:50:13.000000000 +0000
+++ src/gdb/breakpoint.c	2010-03-25 16:43:09.000000000 +0000
@@ -390,13 +390,11 @@ VEC(bp_location_p) *moribund_locations =
 
 static int breakpoint_count;
 
-/* If the last command to create a breakpoint created multiple
-   breakpoints, this holds the start and end breakpoint numbers.  */
-static int multi_start;
-static int multi_end;
-/* True if the last breakpoint set was part of a group set with a
-   single command, e.g., "rbreak".  */
-static int last_was_multi;
+/* The value of `breakpoint_count' before the last command that
+   created breakpoints.  If the last (break-like) command created more
+   than one breakpoint, then the difference between BREAKPOINT_COUNT
+   and PREV_BREAKPOINT_COUNT is more than one.  */
+static int prev_breakpoint_count;
 
 /* Number of last tracepoint made.  */
 
@@ -414,29 +412,31 @@ breakpoint_enabled (struct breakpoint *b
 static void
 set_breakpoint_count (int num)
 {
+  prev_breakpoint_count = breakpoint_count;
   breakpoint_count = num;
-  last_was_multi = 0;
   set_internalvar_integer (lookup_internalvar ("bpnum"), num);
 }
 
+/* Used by `start_rbreak_breakpoints' below, to record the current
+   breakpoint count before "rbreak" creates any breakpoint.  */
+static int rbreak_start_breakpoint_count;
+
 /* Called at the start an "rbreak" command to record the first
    breakpoint made.  */
+
 void
 start_rbreak_breakpoints (void)
 {
-  multi_start = breakpoint_count + 1;
+  rbreak_start_breakpoint_count = breakpoint_count;
 }
 
 /* Called at the end of an "rbreak" command to record the last
    breakpoint made.  */
+
 void
 end_rbreak_breakpoints (void)
 {
-  if (breakpoint_count >= multi_start)
-    {
-      multi_end = breakpoint_count;
-      last_was_multi = 1;
-    }
+  prev_breakpoint_count = rbreak_start_breakpoint_count;
 }
 
 /* Used in run_command to zero the hit count when a new run starts. */
@@ -896,9 +896,14 @@ struct commands_info
 {
   /* True if the command was typed at a tty.  */
   int from_tty;
+
+  /* The breakpoint range spec.  */
+  char *arg;
+
   /* Non-NULL if the body of the commands are being read from this
      already-parsed command.  */
   struct command_line *control;
+
   /* The command lines read from the user, or NULL if they have not
      yet been read.  */
   struct counted_command_line *cmd;
@@ -919,12 +924,23 @@ do_map_commands_command (struct breakpoi
       if (info->control != NULL)
 	l = copy_command_lines (info->control->body_list[0]);
       else
+	{
+	  struct cleanup *old_chain;
+	  char *str;
+
+	  str = xstrprintf (_("Type commands for breakpoint(s) %s, one per line."),
+			    info->arg);
+
+	  old_chain = make_cleanup (xfree, str);
+
+	  l = read_command_lines (str,
+				  info->from_tty, 1,
+				  (breakpoint_is_tracepoint (b)
+				   ? check_tracepoint_command : 0),
+				  b);
 
-	l = read_command_lines (_("Type commands for all specified breakpoints"),
-				info->from_tty, 1,
-				(breakpoint_is_tracepoint (b)
-				 ? check_tracepoint_command : 0),
-				b);
+	  do_cleanups (old_chain);
+	}
 
       info->cmd = alloc_counted_command_line (l);
     }
@@ -957,13 +973,19 @@ commands_command_1 (char *arg, int from_
 
   if (arg == NULL || !*arg)
     {
-      if (last_was_multi)
-	arg = xstrprintf ("%d-%d", multi_start, multi_end);
+      if (breakpoint_count - prev_breakpoint_count > 1)
+	arg = xstrprintf ("%d-%d", prev_breakpoint_count + 1, breakpoint_count);
       else if (breakpoint_count > 0)
 	arg = xstrprintf ("%d", breakpoint_count);
-      make_cleanup (xfree, arg);
+      else
+	arg = NULL;
+
+      if (arg != NULL)
+	make_cleanup (xfree, arg);
     }
 
+  info.arg = arg;
+
   map_breakpoint_numbers (arg, do_map_commands_command, &info);
 
   if (info.cmd == NULL)
@@ -7176,7 +7198,7 @@ create_breakpoint (struct gdbarch *gdbar
   int not_found = 0;
   enum bptype type_wanted;
   int task = 0;
-  int first_bp_set = breakpoint_count + 1;
+  int prev_bkpt_count = breakpoint_count;
 
   sals.sals = NULL;
   sals.nelts = 0;
@@ -7336,9 +7358,7 @@ create_breakpoint (struct gdbarch *gdbar
     {
       warning (_("Multiple breakpoints were set.\n"
 		 "Use the \"delete\" command to delete unwanted breakpoints."));
-      multi_start = first_bp_set;
-      multi_end = breakpoint_count;
-      last_was_multi = 1;
+      prev_breakpoint_count = prev_bkpt_count;
     }
 
   /* That's it.  Discard the cleanups for data inserted into the
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo	2010-03-25 15:45:15.000000000 +0000
+++ src/gdb/doc/gdb.texinfo	2010-03-25 16:54:03.000000000 +0000
@@ -4343,8 +4343,9 @@ watchpoint, or catchpoint set (not to th
 encountered).  If the most recent breakpoints were set with a single
 command, then the @code{commands} will apply to all the breakpoints
 set by that command.  This applies to breakpoints set by
-@code{rbreak}, and also breakpoints set with @code{break} that have
-multiple locations.
+@code{rbreak}, and also applies when a single @code{break} command
+creates multiple breakpoints (@pxref{Ambiguous Expressions,,Ambiguous
+Expressions}).
 @end table
 
 Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
Index: src/gdb/testsuite/gdb.base/commands.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/commands.exp	2010-03-25 16:07:22.000000000 +0000
+++ src/gdb/testsuite/gdb.base/commands.exp	2010-03-25 16:15:57.000000000 +0000
@@ -299,7 +299,7 @@ proc watchpoint_command_test {} {
 
     send_gdb "commands $wp_id\n"
     gdb_expect {
-      -re "Type commands for all specified breakpoints.*>" {
+      -re "Type commands for breakpoint.*, one per line.*>" {
 	  pass "begin commands on watch"
       }
       -re "$gdb_prompt $" {fail "begin commands on watch"}
@@ -452,7 +452,7 @@ proc bp_deleted_in_command_test {} {
     
     send_gdb "commands\n"
     gdb_expect {
-      -re "Type commands for all specified breakpoints.*>" {
+      -re "Type commands for breakpoint.*>" {
           pass "begin commands in bp_deleted_in_command_test"
       }
       -re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
@@ -519,7 +519,7 @@ proc temporary_breakpoint_commands {} {
     
     send_gdb "commands\n"
     gdb_expect {
-	-re "Type commands for all specified breakpoints.*>" {
+	-re "Type commands for breakpoint.*>" {
 	    pass "begin commands in bp_deleted_in_command_test"
 	}
 	-re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
Index: src/gdb/testsuite/gdb.cp/extern-c.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.cp/extern-c.exp	2010-03-25 16:07:33.000000000 +0000
+++ src/gdb/testsuite/gdb.cp/extern-c.exp	2010-03-25 16:18:27.000000000 +0000
@@ -48,7 +48,7 @@ gdb_test "rbreak c_funcs" \
 # Test that "commands" without an argument puts commands on both
 # breakpoints.
 gdb_test_multiple "commands" "set commands on multiple breakpoints" {
-  -re "Type commands for all specified breakpoints\r\nEnd with a line saying just \"end\".\r\n>$" {
+  -re "Type commands for breakpoint\\(s\\) 3-4, one per line\.\r\nEnd with a line saying just \"end\".\r\n>$" {
     gdb_test_multiple "set \$counter = \$counter + 1\nend" \
       "command details for multiple breakpoints" {
 	-re "$gdb_prompt $" {
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS	2010-03-25 16:44:23.000000000 +0000
+++ src/gdb/NEWS	2010-03-25 16:52:29.000000000 +0000
@@ -14,8 +14,11 @@
   register EAX or 64-bit register RAX.
 
 * The `commands' command now accepts a range of breakpoints to modify.
-  A plain `commands' following an `rbreak' will affect all the
-  breakpoints set by `rbreak'.
+  A plain `commands' following a command that creates multiple
+  breakpoints affects all the breakpoints set by that command.  This
+  applies to breakpoints set by `rbreak', and also applies when a
+  single `break' command creates multiple breakpoints (e.g.,
+  breakpoints on overloaded c++ functions).
 
 * Python scripting
 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-25 17:09         ` Pedro Alves
@ 2010-03-30 20:42           ` Tom Tromey
  2010-04-01 11:47             ` Pedro Alves
  0 siblings, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2010-03-30 20:42 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

>>>>> "Pedro" == Pedro Alves <pedro@codesourcery.com> writes:

Pedro> I have a suggestion for this, in form of a patch.  How
Pedro> about we just print the breakpoint range?  

It makes sense to me.

I think I didn't do this because I thought it would look weird if the
user entered an invalid range specifier.  But on reflection I'm not
concerned about that.

Pedro> WDYT?

It looks reasonable to me, though be sure to incorporate the subsequent
bug fix:

2010-03-26  Tom Tromey  <tromey@redhat.com>

	* breakpoint.c (commands_command_1): Duplicate 'arg'.

Tom

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-03-30 20:42           ` Tom Tromey
@ 2010-04-01 11:47             ` Pedro Alves
  2010-04-01 13:32               ` Eli Zaretskii
  0 siblings, 1 reply; 14+ messages in thread
From: Pedro Alves @ 2010-04-01 11:47 UTC (permalink / raw)
  To: tromey, Eli Zaretskii; +Cc: gdb-patches

On Tuesday 30 March 2010 21:42:42, Tom Tromey wrote:
> >>>>> "Pedro" == Pedro Alves <pedro@codesourcery.com> writes:
> 
> Pedro> I have a suggestion for this, in form of a patch.  How
> Pedro> about we just print the breakpoint range?  
> 
> It makes sense to me.
> 
> I think I didn't do this because I thought it would look weird if the
> user entered an invalid range specifier.  But on reflection I'm not
> concerned about that.

That was my early concern as well, but, trying it out
removed the concern.  See:

 (top-gdb) commands 213-2
 inverted range
 (top-gdb) commands 213-2as0fa
 inverted range
 (top-gdb) commands asdf
 warning: bad breakpoint number at or near 'asdf'
 No breakpoints specified.
 (top-gdb) commands asdf342-3
 warning: bad breakpoint number at or near 'asdf342-3'
 No breakpoints specified.
 (top-gdb) commands main
 warning: bad breakpoint number at or near 'main'
 No breakpoints specified.
 (top-gdb) set $foo=1
 (top-gdb) commands $foo
 Type commands for breakpoint(s) $foo, one per line.
 End with a line saying just "end".

Only the last case made me stop for a second and
consider expanding the variable, but I quickly gave
on the idea (about 10 seconds later).


> Pedro> WDYT?
> 
> It looks reasonable to me, though be sure to incorporate the subsequent
> bug fix:
> 2010-03-26  Tom Tromey  <tromey@redhat.com>
> 
> 	* breakpoint.c (commands_command_1): Duplicate 'arg'.

Thanks, will do.  Below's what I'm re-testing.


Eli, want to take a look at the proposed docs/NEWS changes?  I can
split those into a separate patch if you'd prefer:

> > 	* NEWS: Mention changes to `commands' and `rbreak'.
> > 	* gdb.texinfo (Break Commands): Update.
> 
> I'm also suggesting to adjusting these to better explain that
> this applies when "break" (or similars) creates more than one
> breakpoint.  That is different to creating a breakpoint with
> multiple locations ("multiple locations" are described both
> in the manual and in NEWS); in the multiple locations case,
> "commands" already applied to all locations.  I'm adding
> a cross reference to where the case where multiple breakpoints
> are created is described; that section has a nice example.

-- 
Pedro Alves
2010-04-01  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* breakpoint.c (multi_start, multi_end, last_was_multi): Delete.
	(prev_breakpoint_count): New.
	(set_breakpoint_count): Adjust.
	(rbreak_start_breakpoint_count): New.
	(start_rbreak_breakpoints): Adjust.
	(end_rbreak_breakpoints): Adjust.
	(struct commands_info) <arg>: New field.
	(do_map_commands_command): Tweak output to include breakpoint spec
	range.
	(commands_command_1): Adjust.  Avoid setting an xfree cleanup if
	ARG was empty on entry.  Set INFO's arg.
	(create_breakpoint): Adjust.

	* NEWS: Clarify `commands' changes.

	gdb/doc/
	* gdb.texinfo (Break Commands): Clarify `commands' changes, and
	add cross reference.

	gdb/testsuite/
	* gdb.base/commands.exp: Adjust.
	* gdb.cp/extern-c.exp: Adjust.

---
 gdb/NEWS                            |    7 ++-
 gdb/breakpoint.c                    |   77 +++++++++++++++++++++++-------------
 gdb/doc/gdb.texinfo                 |    5 +-
 gdb/testsuite/gdb.base/commands.exp |    6 +-
 gdb/testsuite/gdb.cp/extern-c.exp   |    2 
 5 files changed, 63 insertions(+), 34 deletions(-)

Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2010-04-01 01:46:33.000000000 +0100
+++ src/gdb/breakpoint.c	2010-04-01 12:41:21.000000000 +0100
@@ -388,13 +388,11 @@ VEC(bp_location_p) *moribund_locations =
 
 static int breakpoint_count;
 
-/* If the last command to create a breakpoint created multiple
-   breakpoints, this holds the start and end breakpoint numbers.  */
-static int multi_start;
-static int multi_end;
-/* True if the last breakpoint set was part of a group set with a
-   single command, e.g., "rbreak".  */
-static int last_was_multi;
+/* The value of `breakpoint_count' before the last command that
+   created breakpoints.  If the last (break-like) command created more
+   than one breakpoint, then the difference between BREAKPOINT_COUNT
+   and PREV_BREAKPOINT_COUNT is more than one.  */
+static int prev_breakpoint_count;
 
 /* Number of last tracepoint made.  */
 
@@ -412,29 +410,31 @@ breakpoint_enabled (struct breakpoint *b
 static void
 set_breakpoint_count (int num)
 {
+  prev_breakpoint_count = breakpoint_count;
   breakpoint_count = num;
-  last_was_multi = 0;
   set_internalvar_integer (lookup_internalvar ("bpnum"), num);
 }
 
+/* Used by `start_rbreak_breakpoints' below, to record the current
+   breakpoint count before "rbreak" creates any breakpoint.  */
+static int rbreak_start_breakpoint_count;
+
 /* Called at the start an "rbreak" command to record the first
    breakpoint made.  */
+
 void
 start_rbreak_breakpoints (void)
 {
-  multi_start = breakpoint_count + 1;
+  rbreak_start_breakpoint_count = breakpoint_count;
 }
 
 /* Called at the end of an "rbreak" command to record the last
    breakpoint made.  */
+
 void
 end_rbreak_breakpoints (void)
 {
-  if (breakpoint_count >= multi_start)
-    {
-      multi_end = breakpoint_count;
-      last_was_multi = 1;
-    }
+  prev_breakpoint_count = rbreak_start_breakpoint_count;
 }
 
 /* Used in run_command to zero the hit count when a new run starts. */
@@ -894,9 +894,14 @@ struct commands_info
 {
   /* True if the command was typed at a tty.  */
   int from_tty;
+
+  /* The breakpoint range spec.  */
+  char *arg;
+
   /* Non-NULL if the body of the commands are being read from this
      already-parsed command.  */
   struct command_line *control;
+
   /* The command lines read from the user, or NULL if they have not
      yet been read.  */
   struct counted_command_line *cmd;
@@ -917,12 +922,23 @@ do_map_commands_command (struct breakpoi
       if (info->control != NULL)
 	l = copy_command_lines (info->control->body_list[0]);
       else
+	{
+	  struct cleanup *old_chain;
+	  char *str;
+
+	  str = xstrprintf (_("Type commands for breakpoint(s) %s, one per line."),
+			    info->arg);
 
-	l = read_command_lines (_("Type commands for all specified breakpoints"),
-				info->from_tty, 1,
-				(breakpoint_is_tracepoint (b)
-				 ? check_tracepoint_command : 0),
-				b);
+	  old_chain = make_cleanup (xfree, str);
+
+	  l = read_command_lines (str,
+				  info->from_tty, 1,
+				  (breakpoint_is_tracepoint (b)
+				   ? check_tracepoint_command : 0),
+				  b);
+
+	  do_cleanups (old_chain);
+	}
 
       info->cmd = alloc_counted_command_line (l);
     }
@@ -955,16 +971,27 @@ commands_command_1 (char *arg, int from_
 
   if (arg == NULL || !*arg)
     {
-      if (last_was_multi)
-	arg = xstrprintf ("%d-%d", multi_start, multi_end);
+      if (breakpoint_count - prev_breakpoint_count > 1)
+	arg = xstrprintf ("%d-%d", prev_breakpoint_count + 1, breakpoint_count);
       else if (breakpoint_count > 0)
 	arg = xstrprintf ("%d", breakpoint_count);
+      else
+	{
+	  /* So that we don't try to free the incoming non-NULL
+	     argument in the cleanup below.  Mapping breakpoint
+	     numbers will fail in this case.  */
+	  arg = NULL;
+	}
     }
   else
     /* The command loop has some static state, so we need to preserve
        our argument.  */
     arg = xstrdup (arg);
-  make_cleanup (xfree, arg);
+
+  if (arg != NULL)
+    make_cleanup (xfree, arg);
+
+  info.arg = arg;
 
   map_breakpoint_numbers (arg, do_map_commands_command, &info);
 
@@ -7239,7 +7266,7 @@ create_breakpoint (struct gdbarch *gdbar
   int not_found = 0;
   enum bptype type_wanted;
   int task = 0;
-  int first_bp_set = breakpoint_count + 1;
+  int prev_bkpt_count = breakpoint_count;
 
   sals.sals = NULL;
   sals.nelts = 0;
@@ -7399,9 +7426,7 @@ create_breakpoint (struct gdbarch *gdbar
     {
       warning (_("Multiple breakpoints were set.\n"
 		 "Use the \"delete\" command to delete unwanted breakpoints."));
-      multi_start = first_bp_set;
-      multi_end = breakpoint_count;
-      last_was_multi = 1;
+      prev_breakpoint_count = prev_bkpt_count;
     }
 
   /* That's it.  Discard the cleanups for data inserted into the
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo	2010-03-31 13:13:56.000000000 +0100
+++ src/gdb/doc/gdb.texinfo	2010-04-01 12:27:19.000000000 +0100
@@ -4343,8 +4343,9 @@ watchpoint, or catchpoint set (not to th
 encountered).  If the most recent breakpoints were set with a single
 command, then the @code{commands} will apply to all the breakpoints
 set by that command.  This applies to breakpoints set by
-@code{rbreak}, and also breakpoints set with @code{break} that have
-multiple locations.
+@code{rbreak}, and also applies when a single @code{break} command
+creates multiple breakpoints (@pxref{Ambiguous Expressions,,Ambiguous
+Expressions}).
 @end table
 
 Pressing @key{RET} as a means of repeating the last @value{GDBN} command is
Index: src/gdb/testsuite/gdb.base/commands.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/commands.exp	2010-03-25 18:22:02.000000000 +0000
+++ src/gdb/testsuite/gdb.base/commands.exp	2010-04-01 12:27:19.000000000 +0100
@@ -299,7 +299,7 @@ proc watchpoint_command_test {} {
 
     send_gdb "commands $wp_id\n"
     gdb_expect {
-      -re "Type commands for all specified breakpoints.*>" {
+      -re "Type commands for breakpoint.*, one per line.*>" {
 	  pass "begin commands on watch"
       }
       -re "$gdb_prompt $" {fail "begin commands on watch"}
@@ -452,7 +452,7 @@ proc bp_deleted_in_command_test {} {
     
     send_gdb "commands\n"
     gdb_expect {
-      -re "Type commands for all specified breakpoints.*>" {
+      -re "Type commands for breakpoint.*>" {
           pass "begin commands in bp_deleted_in_command_test"
       }
       -re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
@@ -519,7 +519,7 @@ proc temporary_breakpoint_commands {} {
     
     send_gdb "commands\n"
     gdb_expect {
-	-re "Type commands for all specified breakpoints.*>" {
+	-re "Type commands for breakpoint.*>" {
 	    pass "begin commands in bp_deleted_in_command_test"
 	}
 	-re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"}
Index: src/gdb/testsuite/gdb.cp/extern-c.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.cp/extern-c.exp	2010-03-25 18:22:02.000000000 +0000
+++ src/gdb/testsuite/gdb.cp/extern-c.exp	2010-04-01 12:27:19.000000000 +0100
@@ -48,7 +48,7 @@ gdb_test "rbreak c_funcs" \
 # Test that "commands" without an argument puts commands on both
 # breakpoints.
 gdb_test_multiple "commands" "set commands on multiple breakpoints" {
-  -re "Type commands for all specified breakpoints\r\nEnd with a line saying just \"end\".\r\n>$" {
+  -re "Type commands for breakpoint\\(s\\) 3-4, one per line\.\r\nEnd with a line saying just \"end\".\r\n>$" {
     gdb_test_multiple "set \$counter = \$counter + 1\nend" \
       "command details for multiple breakpoints" {
 	-re "$gdb_prompt $" {
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS	2010-03-30 22:45:15.000000000 +0100
+++ src/gdb/NEWS	2010-04-01 12:27:19.000000000 +0100
@@ -17,8 +17,11 @@
   register EAX or 64-bit register RAX.
 
 * The `commands' command now accepts a range of breakpoints to modify.
-  A plain `commands' following an `rbreak' will affect all the
-  breakpoints set by `rbreak'.
+  A plain `commands' following a command that creates multiple
+  breakpoints affects all the breakpoints set by that command.  This
+  applies to breakpoints set by `rbreak', and also applies when a
+  single `break' command creates multiple breakpoints (e.g.,
+  breakpoints on overloaded c++ functions).
 
 * Python scripting
 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [2/2] RFC: let "commands" affect multiple breakpoints
  2010-04-01 11:47             ` Pedro Alves
@ 2010-04-01 13:32               ` Eli Zaretskii
  0 siblings, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2010-04-01 13:32 UTC (permalink / raw)
  To: Pedro Alves; +Cc: tromey, gdb-patches

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Thu, 1 Apr 2010 12:46:40 +0100
> Cc: gdb-patches@sourceware.org
> 
> Eli, want to take a look at the proposed docs/NEWS changes?

They are fine with me.  Thanks.

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2010-04-01 13:32 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-10  3:54 [2/2] RFC: let "commands" affect multiple breakpoints Tom Tromey
2010-03-10 16:34 ` Tom Tromey
2010-03-10 17:05 ` Pedro Alves
2010-03-11 21:42   ` Tom Tromey
2010-03-23  4:23     ` Tom Tromey
2010-03-23 17:24       ` Eli Zaretskii
2010-03-24 21:21       ` Tom Tromey
2010-03-25 17:09         ` Pedro Alves
2010-03-30 20:42           ` Tom Tromey
2010-04-01 11:47             ` Pedro Alves
2010-04-01 13:32               ` Eli Zaretskii
2010-03-10 17:37 ` Eli Zaretskii
2010-03-11 20:50   ` Tom Tromey
2010-03-12  7:53     ` Eli Zaretskii

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).