aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog19
-rw-r--r--gdb/breakpoint.c11
-rw-r--r--gdb/breakpoint.h10
-rw-r--r--gdb/gdbthread.h3
-rw-r--r--gdb/infrun.c54
-rw-r--r--gdb/testsuite/ChangeLog6
-rw-r--r--gdb/testsuite/gdb.threads/break-while-running.exp35
-rw-r--r--gdb/thread.c44
8 files changed, 144 insertions, 38 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 18ebca4..748d61d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,24 @@
2014-10-02 Pedro Alves <palves@redhat.com>
+ * breakpoint.c (breakpoints_should_be_inserted_now): Use
+ threads_are_executing.
+ * breakpoint.h (breakpoints_should_be_inserted_now): Add
+ describing comment.
+ * gdbthread.h (threads_are_executing): Declare.
+ (handle_signal_stop) <random signals>: Don't print about the
+ signal here if stopping.
+ (end_stepping_range): Don't notify observers here.
+ (normal_stop): Update the thread list. If stopped by a random
+ signal or a stepping range ended, notify observers.
+ * thread.c (threads_executing): New global.
+ (init_thread_list): Clear 'threads_executing'.
+ (set_executing): Set or clear 'threads_executing'.
+ (threads_are_executing): New function.
+ (update_threads_executing): New function.
+ (update_thread_list): Use it.
+
+2014-10-02 Pedro Alves <palves@redhat.com>
+
PR breakpoints/17431
* breakpoint.c (update_breakpoints_after_exec): Don't create
overlay, longjmp, std terminate nor exception breakpoints here.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 684f74c..7da88b0 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -473,6 +473,8 @@ show_always_inserted_mode (struct ui_file *file, int from_tty,
value);
}
+/* See breakpoint.h. */
+
int
breakpoints_should_be_inserted_now (void)
{
@@ -485,8 +487,6 @@ breakpoints_should_be_inserted_now (void)
}
else if (target_has_execution)
{
- struct thread_info *tp;
-
if (always_inserted_mode)
{
/* The user wants breakpoints inserted even if all threads
@@ -494,11 +494,8 @@ breakpoints_should_be_inserted_now (void)
return 1;
}
- ALL_NON_EXITED_THREADS (tp)
- {
- if (tp->executing)
- return 1;
- }
+ if (threads_are_executing ())
+ return 1;
}
return 0;
}
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index e191c10..d65405f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1491,6 +1491,16 @@ extern void breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
const gdb_byte *writebuf_org,
ULONGEST memaddr, LONGEST len);
+/* Return true if breakpoints should be inserted now. That'll be the
+ case if either:
+
+ - the target has global breakpoints.
+
+ - "breakpoint always-inserted" is on, and the target has
+ execution.
+
+ - threads are executing.
+*/
extern int breakpoints_should_be_inserted_now (void);
/* Called each time new event from target is processed.
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 6768491..26ca925 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -381,6 +381,9 @@ extern void set_executing (ptid_t ptid, int executing);
/* Reports if thread PTID is executing. */
extern int is_executing (ptid_t ptid);
+/* True if any (known or unknown) thread is or may be executing. */
+extern int threads_are_executing (void);
+
/* Merge the executing property of thread PTID over to its thread
state property (frontend running/stopped view).
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 728c160..8137eb3 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4436,13 +4436,6 @@ handle_signal_stop (struct execution_control_state *ecs)
stopped_by_random_signal = 1;
- if (signal_print[ecs->event_thread->suspend.stop_signal])
- {
- /* The signal table tells us to print about this signal. */
- printed = 1;
- target_terminal_ours_for_output ();
- observer_notify_signal_received (ecs->event_thread->suspend.stop_signal);
- }
/* Always stop on signals if we're either just gaining control
of the program, or the user explicitly requested this thread
to remain stopped. */
@@ -4454,10 +4447,17 @@ handle_signal_stop (struct execution_control_state *ecs)
stop_waiting (ecs);
return;
}
- /* If not going to stop, give terminal back
- if we took it away. */
- else if (printed)
- target_terminal_inferior ();
+
+ /* Notify observers the signal has "handle print" set. Note we
+ returned early above if stopping; normal_stop handles the
+ printing in that case. */
+ if (signal_print[ecs->event_thread->suspend.stop_signal])
+ {
+ /* The signal table tells us to print about this signal. */
+ target_terminal_ours_for_output ();
+ observer_notify_signal_received (ecs->event_thread->suspend.stop_signal);
+ target_terminal_inferior ();
+ }
/* Clear the signal if it should not be passed. */
if (signal_program[ecs->event_thread->suspend.stop_signal] == 0)
@@ -6092,15 +6092,12 @@ prepare_to_wait (struct execution_control_state *ecs)
}
/* We are done with the step range of a step/next/si/ni command.
- Called once for each n of a "step n" operation. Notify observers
- if not in the middle of doing a "step N" operation for N > 1. */
+ Called once for each n of a "step n" operation. */
static void
end_stepping_range (struct execution_control_state *ecs)
{
ecs->event_thread->control.stop_step = 1;
- if (!ecs->event_thread->step_multi)
- observer_notify_end_stepping_range ();
stop_waiting (ecs);
}
@@ -6311,6 +6308,19 @@ normal_stop (void)
&& last.kind != TARGET_WAITKIND_NO_RESUMED)
make_cleanup (finish_thread_state_cleanup, &inferior_ptid);
+ /* As we're presenting a stop, and potentially removing breakpoints,
+ update the thread list so we can tell whether there are threads
+ running on the target. With target remote, for example, we can
+ only learn about new threads when we explicitly update the thread
+ list. Do this before notifying the interpreters about signal
+ stops, end of stepping ranges, etc., so that the "new thread"
+ output is emitted before e.g., "Program received signal FOO",
+ instead of after. */
+ update_thread_list ();
+
+ if (last.kind == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
+ observer_notify_signal_received (inferior_thread ()->suspend.stop_signal);
+
/* As with the notification of thread events, we want to delay
notifying the user that we've switched thread context until
the inferior actually stops.
@@ -6349,6 +6359,7 @@ normal_stop (void)
printf_filtered (_("No unwaited-for children left.\n"));
}
+ /* Note: this depends on the update_thread_list call above. */
if (!breakpoints_should_be_inserted_now () && target_has_execution)
{
if (remove_breakpoints ())
@@ -6366,14 +6377,19 @@ normal_stop (void)
if (stopped_by_random_signal)
disable_current_display ();
- /* Don't print a message if in the middle of doing a "step n"
- operation for n > 1 */
+ /* Notify observers if we finished a "step"-like command, etc. */
if (target_has_execution
&& last.kind != TARGET_WAITKIND_SIGNALLED
&& last.kind != TARGET_WAITKIND_EXITED
- && inferior_thread ()->step_multi
&& inferior_thread ()->control.stop_step)
- goto done;
+ {
+ /* But not if if in the middle of doing a "step n" operation for
+ n > 1 */
+ if (inferior_thread ()->step_multi)
+ goto done;
+
+ observer_notify_end_stepping_range ();
+ }
target_terminal_ours ();
async_enable_stdin ();
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 87f3684..3579660 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,11 @@
2014-10-02 Pedro Alves <palves@redhat.com>
+ * gdb.threads/break-while-running.exp (test): Add new
+ 'update_thread_list' argument. Skip "info threads" if false.
+ (top level): Add new 'update_thread_list' axis.
+
+2014-10-02 Pedro Alves <palves@redhat.com>
+
PR breakpoints/17431
* gdb.base/execl-update-breakpoints.c: New file.
* gdb.base/execl-update-breakpoints.exp: New file.
diff --git a/gdb/testsuite/gdb.threads/break-while-running.exp b/gdb/testsuite/gdb.threads/break-while-running.exp
index 690d6ab..ea28bf0 100644
--- a/gdb/testsuite/gdb.threads/break-while-running.exp
+++ b/gdb/testsuite/gdb.threads/break-while-running.exp
@@ -28,11 +28,13 @@ if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug pthreads}
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.
+# The test proper. UPDATE_THREAD_LIST indicates whether we should do
+# an "info threads" to sync the thread list after the first stop.
+# ALWAYS_INSERTED indicates whether testing in "breakpoint
+# always-inserted" mode. NON_STOP indicates whether we're testing in
+# non-stop, or all-stop mode.
-proc test { always_inserted non_stop } {
+proc test { update_thread_list always_inserted non_stop } {
global srcfile binfile
global gdb_prompt
global decimal
@@ -70,9 +72,15 @@ proc test { always_inserted non_stop } {
gdb_test "thread 1" "Switching to .*" "switch back to main thread"
}
- gdb_test "info threads" \
- "\\\(running\\\).*\\\(running\\\).* main .*" \
- "only main stopped"
+ # Test with and without pulling the thread list explicitly with
+ # "info threads". GDB should be able to figure out itself whether
+ # the target is running and thus breakpoints should be inserted,
+ # without the user explicitly fetching the thread list.
+ if {$update_thread_list} {
+ 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
@@ -141,11 +149,14 @@ proc test { always_inserted non_stop } {
}
}
-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
+foreach update_thread_list { true false } {
+ foreach always_inserted { "off" "on" } {
+ foreach non_stop { "off" "on" } {
+ set stop_mode [expr ($non_stop=="off")?"all-stop":"non-stop"]
+ set update_list_mode [expr ($update_thread_list)?"w/ithr":"wo/ithr"]
+ with_test_prefix "$update_list_mode: always-inserted $always_inserted: $stop_mode" {
+ test $update_thread_list $always_inserted $non_stop
+ }
}
}
}
diff --git a/gdb/thread.c b/gdb/thread.c
index bceaf49..ac1d8a1 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -56,6 +56,13 @@ void _initialize_thread (void);
struct thread_info *thread_list = NULL;
static int highest_thread_num;
+/* True if any thread is, or may be executing. We need to track this
+ separately because until we fully sync the thread list, we won't
+ know whether the target is fully stopped, even if we see stop
+ events for all known threads, because any of those threads may have
+ spawned new threads we haven't heard of yet. */
+static int threads_executing;
+
static void thread_command (char *tidstr, int from_tty);
static void thread_apply_all_command (char *, int);
static int thread_alive (struct thread_info *);
@@ -167,6 +174,7 @@ init_thread_list (void)
}
thread_list = NULL;
+ threads_executing = 0;
}
/* Allocate a new thread with target id PTID and add it to the thread
@@ -702,6 +710,22 @@ set_executing (ptid_t ptid, int executing)
gdb_assert (tp);
tp->executing = executing;
}
+
+ /* It only takes one running thread to spawn more threads.*/
+ if (executing)
+ threads_executing = 1;
+ /* Only clear the flag if the caller is telling us everything is
+ stopped. */
+ else if (ptid_equal (minus_one_ptid, ptid))
+ threads_executing = 0;
+}
+
+/* See gdbthread.h. */
+
+int
+threads_are_executing (void)
+{
+ return threads_executing;
}
void
@@ -1501,11 +1525,31 @@ gdb_thread_select (struct ui_out *uiout, char *tidstr, char **error_message)
return GDB_RC_OK;
}
+/* Update the 'threads_executing' global based on the threads we know
+ about right now. */
+
+static void
+update_threads_executing (void)
+{
+ struct thread_info *tp;
+
+ threads_executing = 0;
+ ALL_NON_EXITED_THREADS (tp)
+ {
+ if (tp->executing)
+ {
+ threads_executing = 1;
+ break;
+ }
+ }
+}
+
void
update_thread_list (void)
{
prune_threads ();
target_find_new_threads ();
+ update_threads_executing ();
}
/* Return a new value for the selected thread's id. Return a value of 0 if