* [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 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 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
* 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-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
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