summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog31
-rw-r--r--gdb/NEWS7
-rw-r--r--gdb/breakpoint.c90
-rw-r--r--gdb/breakpoint.h2
-rw-r--r--gdb/doc/ChangeLog6
-rw-r--r--gdb/doc/gdb.texinfo13
-rw-r--r--gdb/infrun.c5
-rw-r--r--gdb/remote.c5
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.threads/break-while-running.c101
-rw-r--r--gdb/testsuite/gdb.threads/break-while-running.exp151
11 files changed, 361 insertions, 55 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b91dc72da15..90a991d39d0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,36 @@
2014-09-22 Pedro Alves <palves@redhat.com>
+ * NEWS: Mention merge of "breakpoint always-inserted" modes "off"
+ and "auto" merged.
+ * breakpoint.c (enum ugll_insert_mode): New enum.
+ (always_inserted_mode): Now a plain boolean.
+ (show_always_inserted_mode): No longer handle AUTO_BOOLEAN_AUTO.
+ (breakpoints_always_inserted_mode): Delete.
+ (breakpoints_should_be_inserted_now): New function.
+ (insert_breakpoints): Pass UGLL_INSERT to
+ update_global_location_list instead of calling
+ insert_breakpoint_locations manually.
+ (create_solib_event_breakpoint_1): New, factored out from ...
+ (create_solib_event_breakpoint): ... this.
+ (create_and_insert_solib_event_breakpoint): Use
+ create_solib_event_breakpoint_1 instead of calling
+ insert_breakpoint_locations manually.
+ (update_global_location_list): Change parameter type from boolean
+ to enum ugll_insert_mode. All callers adjusted. Adjust to use
+ breakpoints_should_be_inserted_now and handle UGLL_INSERT.
+ (update_global_location_list_nothrow): Change parameter type from
+ boolean to enum ugll_insert_mode.
+ (_initialize_breakpoint): "breakpoint always-inserted" option is
+ now a boolean command. Update help text.
+ * breakpoint.h (breakpoints_always_inserted_mode): Delete declaration.
+ (breakpoints_should_be_inserted_now): New declaration.
+ * infrun.c (handle_inferior_event) <TARGET_WAITKIND_LOADED>:
+ Remove breakpoints_always_inserted_mode check.
+ (normal_stop): Adjust to use breakpoints_should_be_inserted_now.
+ * remote.c (remote_start_remote): Likewise.
+
+2014-09-22 Pedro Alves <palves@redhat.com>
+
* breakpoint.c (enum ugll_insert_mode): Add UGLL_INSERT.
(insert_breakpoints): Don't call insert_breakpoint_locations here.
Instead, pass UGLL_INSERT to update_global_location_list.
diff --git a/gdb/NEWS b/gdb/NEWS
index 82ee57bd2b7..11326f17a15 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -33,6 +33,13 @@ queue-signal signal-name-or-number
confirmation if the program had stopped for a signal and the user
switched threads meanwhile.
+* "breakpoint always-inserted" modes "off" and "auto" merged.
+
+ Now, when 'breakpoint always-inserted mode' is set to "off", GDB
+ won't remove breakpoints from the target until all threads stop,
+ even in non-stop mode. The "auto" mode has been removed, and "off"
+ is now the default mode.
+
*** Changes in GDB 7.8
* New command line options
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 3f372de8992..3675b4fd689 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -258,12 +258,17 @@ enum ugll_insert_mode
the inferior. */
UGLL_DONT_INSERT,
- /* May insert breakpoints if breakpoints_always_inserted_mode is
- true. */
+ /* May insert breakpoints iff breakpoints_should_be_inserted_now
+ claims breakpoints should be inserted now. */
UGLL_MAY_INSERT,
- /* Insert locations now, even if breakpoints_always_inserted_mode is
- false. */
+ /* Insert locations now, irrespective of
+ breakpoints_should_be_inserted_now. E.g., say all threads are
+ stopped right now, and the user did "continue". We need to
+ insert breakpoints _before_ resuming the target, but
+ UGLL_MAY_INSERT wouldn't insert them, because
+ breakpoints_should_be_inserted_now returns false at that point,
+ as no thread is running yet. */
UGLL_INSERT
};
@@ -451,34 +456,51 @@ show_automatic_hardware_breakpoints (struct ui_file *file, int from_tty,
value);
}
-/* If on, gdb will keep breakpoints inserted even as inferior is
- stopped, and immediately insert any new breakpoints. If off, gdb
- will insert breakpoints into inferior only when resuming it, and
- will remove breakpoints upon stop. If auto, GDB will behave as ON
- if in non-stop mode, and as OFF if all-stop mode.*/
-
-static enum auto_boolean always_inserted_mode = AUTO_BOOLEAN_AUTO;
+/* If on, GDB keeps breakpoints inserted even if the inferior is
+ stopped, and immediately inserts any new breakpoints as soon as
+ they're created. If off (default), GDB keeps breakpoints off of
+ the target as long as possible. That is, it delays inserting
+ breakpoints until the next resume, and removes them again when the
+ target fully stops. This is a bit safer in case GDB crashes while
+ processing user input. */
+static int always_inserted_mode = 0;
static void
show_always_inserted_mode (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- if (always_inserted_mode == AUTO_BOOLEAN_AUTO)
- fprintf_filtered (file,
- _("Always inserted breakpoint "
- "mode is %s (currently %s).\n"),
- value,
- breakpoints_always_inserted_mode () ? "on" : "off");
- else
- fprintf_filtered (file, _("Always inserted breakpoint mode is %s.\n"),
- value);
+ fprintf_filtered (file, _("Always inserted breakpoint mode is %s.\n"),
+ value);
}
int
-breakpoints_always_inserted_mode (void)
+breakpoints_should_be_inserted_now (void)
{
- return (always_inserted_mode == AUTO_BOOLEAN_TRUE
- || (always_inserted_mode == AUTO_BOOLEAN_AUTO && non_stop));
+ if (gdbarch_has_global_breakpoints (target_gdbarch ()))
+ {
+ /* If breakpoints are global, they should be inserted even if no
+ thread under gdb's control is running, or even if there are
+ no threads under GDB's control yet. */
+ return 1;
+ }
+ else if (target_has_execution)
+ {
+ struct thread_info *tp;
+
+ if (always_inserted_mode)
+ {
+ /* The user wants breakpoints inserted even if all threads
+ are stopped. */
+ return 1;
+ }
+
+ ALL_NON_EXITED_THREADS (tp)
+ {
+ if (tp->executing)
+ return 1;
+ }
+ }
+ return 0;
}
static const char condition_evaluation_both[] = "host or target";
@@ -12930,10 +12952,7 @@ update_global_location_list (enum ugll_insert_mode insert_mode)
"a permanent breakpoint"));
}
- if (insert_mode == UGLL_INSERT
- || (breakpoints_always_inserted_mode ()
- && (have_live_inferiors ()
- || (gdbarch_has_global_breakpoints (target_gdbarch ())))))
+ if (insert_mode == UGLL_INSERT || breakpoints_should_be_inserted_now ())
{
if (insert_mode != UGLL_DONT_INSERT)
insert_breakpoint_locations ();
@@ -17020,18 +17039,15 @@ a warning will be emitted for such breakpoints."),
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
- add_setshow_auto_boolean_cmd ("always-inserted", class_support,
- &always_inserted_mode, _("\
+ add_setshow_boolean_cmd ("always-inserted", class_support,
+ &always_inserted_mode, _("\
Set mode for inserting breakpoints."), _("\
Show mode for inserting breakpoints."), _("\
-When this mode is off, breakpoints are inserted in inferior when it is\n\
-resumed, and removed when execution stops. When this mode is on,\n\
-breakpoints are inserted immediately and removed only when the user\n\
-deletes the breakpoint. When this mode is auto (which is the default),\n\
-the behaviour depends on the non-stop setting (see help set non-stop).\n\
-In this case, if gdb is controlling the inferior in non-stop mode, gdb\n\
-behaves as if always-inserted mode is on; if gdb is controlling the\n\
-inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
+When this mode is on, breakpoints are inserted immediately as soon as\n\
+they're created, kept inserted even when execution stops, and removed\n\
+only when the user deletes them. When this mode is off (the default),\n\
+breakpoints are inserted only when execution continues, and removed\n\
+when execution stops."),
NULL,
&show_always_inserted_mode,
&breakpoint_set_cmdlist,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 00c88029452..e191c10f9ce 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1491,7 +1491,7 @@ extern void breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
const gdb_byte *writebuf_org,
ULONGEST memaddr, LONGEST len);
-extern int breakpoints_always_inserted_mode (void);
+extern int breakpoints_should_be_inserted_now (void);
/* Called each time new event from target is processed.
Retires previously deleted breakpoint locations that
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index b5fac5a9441..d77a80eaf4b 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,9 @@
+2014-09-22 Pedro Alves <palves@redhat.com>
+
+ * gdb.texinfo (Set Breaks): Document that "set breakpoint
+ always-inserted off" is the default mode now. Delete
+ documentation of "set breakpoint always-inserted auto".
+
2014-09-18 Doug Evans <dje@google.com>
* python.texi (Symbol Tables In Python): Document "producer"
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1bb1c0c3144..537fae8efd0 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3850,22 +3850,13 @@ This behavior can be controlled with the following commands::
@item set breakpoint always-inserted off
All breakpoints, including newly added by the user, are inserted in
the target only when the target is resumed. All breakpoints are
-removed from the target when it stops.
+removed from the target when it stops. This is the default mode.
@item set breakpoint always-inserted on
Causes all breakpoints to be inserted in the target at all times. If
the user adds a new breakpoint, or changes an existing breakpoint, the
breakpoints in the target are updated immediately. A breakpoint is
-removed from the target only when breakpoint itself is removed.
-
-@cindex non-stop mode, and @code{breakpoint always-inserted}
-@item set breakpoint always-inserted auto
-This is the default mode. If @value{GDBN} is controlling the inferior
-in non-stop mode (@pxref{Non-Stop Mode}), gdb behaves as if
-@code{breakpoint always-inserted} mode is on. If @value{GDBN} is
-controlling the inferior in all-stop mode, @value{GDBN} behaves as if
-@code{breakpoint always-inserted} mode is off.
-@end table
+removed from the target only when breakpoint itself is deleted.
@value{GDBN} handles conditional breakpoints by evaluating these conditions
when a breakpoint breaks. If the condition is true, then the process being
diff --git a/gdb/infrun.c b/gdb/infrun.c
index c18267f779d..3725f2da086 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3448,8 +3448,7 @@ handle_inferior_event (struct execution_control_state *ecs)
{
/* Loading of shared libraries might have changed breakpoint
addresses. Make sure new breakpoints are inserted. */
- if (stop_soon == NO_STOP_QUIETLY
- && !breakpoints_always_inserted_mode ())
+ if (stop_soon == NO_STOP_QUIETLY)
insert_breakpoints ();
resume (0, GDB_SIGNAL_0);
prepare_to_wait (ecs);
@@ -6110,7 +6109,7 @@ normal_stop (void)
printf_filtered (_("No unwaited-for children left.\n"));
}
- if (!breakpoints_always_inserted_mode () && target_has_execution)
+ if (!breakpoints_should_be_inserted_now () && target_has_execution)
{
if (remove_breakpoints ())
{
diff --git a/gdb/remote.c b/gdb/remote.c
index 357e9f2c912..41ea0129e33 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -3604,9 +3604,8 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
up. */
rs->starting_up = 0;
- /* If breakpoints are global, insert them now. */
- if (gdbarch_has_global_breakpoints (target_gdbarch ())
- && breakpoints_always_inserted_mode ())
+ /* Maybe breakpoints are global and need to be inserted now. */
+ if (breakpoints_should_be_inserted_now ())
insert_breakpoints ();
}
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 67c7f822aff..539a983da0d 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2014-09-22 Pedro Alves <palves@redhat.com>
+
+ * gdb.threads/break-while-running.exp: New file.
+ * gdb.threads/break-while-running.c: New file.
+
2014-09-19 Yao Qi <yao@codesourcery.com>
* gdb.dwarf2/dw2-var-zero-addr.exp: Move test into new proc test.
diff --git a/gdb/testsuite/gdb.threads/break-while-running.c b/gdb/testsuite/gdb.threads/break-while-running.c
new file mode 100644
index 00000000000..20695ee4e24
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/break-while-running.c
@@ -0,0 +1,101 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2014 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <pthread.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+pthread_barrier_t barrier;
+
+volatile int second_child;
+
+void
+breakpoint_function (void)
+{
+ /* GDB sets a breakpoint in this function. */
+}
+
+void *
+child_function_0 (void *arg)
+{
+ volatile unsigned int counter = 1;
+
+ pthread_barrier_wait (&barrier);
+
+ while (counter > 0)
+ {
+ counter++;
+ usleep (1);
+
+ if (second_child)
+ continue;
+
+ breakpoint_function ();
+ }
+
+ pthread_exit (NULL);
+}
+
+void *
+child_function_1 (void *arg)
+{
+ volatile unsigned int counter = 1;
+
+ pthread_barrier_wait (&barrier);
+
+ while (counter > 0)
+ {
+ counter++;
+ usleep (1);
+
+ if (!second_child)
+ continue;
+
+ breakpoint_function ();
+ }
+
+ pthread_exit (NULL);
+}
+
+static int
+wait_threads (void)
+{
+ return 1; /* in wait_threads */
+}
+
+int
+main (void)
+{
+ pthread_t child_thread[2];
+ int res;
+
+ pthread_barrier_init (&barrier, NULL, 3);
+
+ res = pthread_create (&child_thread[0], NULL, child_function_0, NULL);
+ assert (res == 0);
+ res = pthread_create (&child_thread[1], NULL, child_function_1, NULL);
+ assert (res == 0);
+
+ pthread_barrier_wait (&barrier);
+ wait_threads (); /* set wait-thread breakpoint here */
+
+ pthread_join (child_thread[0], NULL);
+ pthread_join (child_thread[1], NULL);
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/gdb/testsuite/gdb.threads/break-while-running.exp b/gdb/testsuite/gdb.threads/break-while-running.exp
new file mode 100644
index 00000000000..690d6ab9eb6
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/break-while-running.exp
@@ -0,0 +1,151 @@
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test that:
+#
+# - setting a breakpoint while a thread is running results in the
+# breakpoint being inserted immediately.
+#
+# - if breakpoint always-inserted mode is off, GDB doesn't remove
+# breakpoints from the target when a thread stops, if there are
+# still threads running.
+
+standard_testfile
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} {
+ return -1
+}
+
+# The test proper. NON_STOP indicates whether we're testing in
+# non-stop, or all-stop mode. ALWAYS_INSERTED indicates whether
+# testing in "breakpoint always-inserted" mode.
+
+proc test { always_inserted non_stop } {
+ global srcfile binfile
+ global gdb_prompt
+ global decimal
+
+ clean_restart $binfile
+
+ gdb_test_no_output "set non-stop $non_stop"
+ gdb_test_no_output "set breakpoint always-inserted $always_inserted"
+
+ if ![runto_main] {
+ return -1
+ }
+
+ # In all-stop, check whether we're testing with the remote or
+ # extended-remote targets. If so, skip the tests, as with the
+ # RSP, we can't issue commands until the target replies to vCont.
+ # Not an issue with the non-stop RSP variant, which has a
+ # non-blocking vCont.
+ if {$non_stop=="off" && [gdb_is_target_remote]} {
+ return -1
+ }
+
+ gdb_breakpoint [gdb_get_line_number "set wait-thread breakpoint here"]
+ gdb_continue_to_breakpoint "run to wait-thread breakpoint"
+
+ delete_breakpoints
+
+ # Leave the main thread stopped, so GDB can poke at memory freely.
+ if {$non_stop == "off"} {
+ gdb_test_no_output "set scheduler-locking on"
+ gdb_test "thread 2" "Switching to .*"
+ gdb_test "continue &" "Continuing\." "continuing thread 2"
+ gdb_test "thread 3" "Switching to .*"
+ gdb_test "continue &" "Continuing\." "continuing thread 3"
+ gdb_test "thread 1" "Switching to .*" "switch back to main thread"
+ }
+
+ gdb_test "info threads" \
+ "\\\(running\\\).*\\\(running\\\).* main .*" \
+ "only main stopped"
+
+ # Don't use gdb_test as it's racy in this case -- gdb_test matches
+ # the prompt with an end anchor. Sometimes expect will manage to
+ # read the breakpoint hit output while still processing this test,
+ # defeating the anchor.
+ set test "set breakpoint while a thread is running"
+ gdb_test_multiple "break breakpoint_function" $test {
+ -re "Breakpoint $decimal at .*: file .*$srcfile.*\r\n$gdb_prompt " {
+ pass $test
+ }
+ -re "$gdb_prompt " {
+ fail $test
+ }
+ }
+
+ # Check that the breakpoint is hit. Can't use gdb_test here, as
+ # no prompt is expected to come out.
+ set test "breakpoint is hit"
+ gdb_test_multiple "" $test {
+ -re "Breakpoint .*, breakpoint_function \[^\r\n\]+" {
+ pass $test
+ }
+ }
+
+ if {$non_stop == "on"} {
+ gdb_test "info threads" \
+ "\\\(running\\\).* breakpoint_function .* main .*" \
+ "one thread running"
+
+ # Unblock the other thread, which should then trip on the same
+ # breakpoint, unless GDB removed it by mistake. Can't use
+ # gdb_test here for the same reasons as above.
+ set test "unblock second thread"
+ gdb_test_multiple "print second_child = 1" $test {
+ -re " = 1\r\n$gdb_prompt " {
+ pass $test
+ }
+ -re "$gdb_prompt " {
+ fail $test
+ }
+ }
+
+ set test "breakpoint on second child is hit"
+ gdb_test_multiple "" $test {
+ -re "Breakpoint .*, breakpoint_function \[^\r\n\]+" {
+ pass $test
+ }
+ }
+
+ gdb_test "info threads" \
+ " breakpoint_function .* breakpoint_function .* main .*" \
+ "all threads stopped"
+ } else {
+ # This test is not merged with the non-stop one because in
+ # all-stop we don't know where the other thread stops (inside
+ # usleep, for example).
+ set test "all threads stopped"
+ gdb_test_multiple "info threads" "$test" {
+ -re "\\\(running\\\).*$gdb_prompt $" {
+ fail $test
+ }
+ -re "breakpoint_function .* main .*$gdb_prompt $" {
+ pass $test
+ }
+ }
+ }
+}
+
+foreach always_inserted { "off" "on" } {
+ foreach non_stop { "off" "on" } {
+ set stop_mode [expr ($non_stop=="off")?"all-stop":"non-stop"]
+ with_test_prefix "always-inserted $always_inserted: $stop_mode" {
+ test $always_inserted $non_stop
+ }
+ }
+}