aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/infrun.c15
-rw-r--r--gdb/remote.c9
-rw-r--r--gdb/target/target.c1
-rw-r--r--gdb/target/target.h4
4 files changed, 24 insertions, 5 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index e1e761c..0a189d0 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2516,24 +2516,29 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
else
target_pass_signals (signal_pass);
- /* Request that the target report thread-{created,cloned} events in
- the following situations:
+ /* Request that the target report thread-{created,cloned,exited}
+ events in the following situations:
- If we are performing an in-line step-over-breakpoint, then we
will remove a breakpoint from the target and only run the
current thread. We don't want any new thread (spawned by the
- step) to start running, as it might miss the breakpoint.
+ step) to start running, as it might miss the breakpoint. We
+ need to clear the step-over state if the stepped thread exits,
+ so we also enable thread-exit events.
- If we are stepping over a breakpoint out of line (displaced
stepping) then we won't remove a breakpoint from the target,
but, if the step spawns a new clone thread, then we will need
to fixup the $pc address in the clone child too, so we need it
- to start stopped.
+ to start stopped. We need to release the displaced stepping
+ buffer if the stepped thread exits, so we also enable
+ thread-exit events.
*/
if (step_over_info_valid_p ()
|| displaced_step_in_progress_thread (tp))
{
- gdb_thread_options options = GDB_THREAD_OPTION_CLONE;
+ gdb_thread_options options
+ = GDB_THREAD_OPTION_CLONE | GDB_THREAD_OPTION_EXIT;
if (target_supports_set_thread_options (options))
tp->set_thread_options (options);
else
diff --git a/gdb/remote.c b/gdb/remote.c
index eb537fc..ce5adda 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4206,6 +4206,15 @@ remote_target::update_thread_list ()
if (has_single_non_exited_thread (tp->inf))
continue;
+ /* Do not remove the thread if we've requested to be
+ notified of its exit. For example, the thread may be
+ displaced stepping, infrun will need to handle the
+ exit event, and displaced stepping info is recorded
+ in the thread object. If we deleted the thread now,
+ we'd lose that info. */
+ if ((tp->thread_options () & GDB_THREAD_OPTION_EXIT) != 0)
+ continue;
+
/* Not found. */
delete_thread (tp);
}
diff --git a/gdb/target/target.c b/gdb/target/target.c
index 3af7d73..58d0f63 100644
--- a/gdb/target/target.c
+++ b/gdb/target/target.c
@@ -196,6 +196,7 @@ to_string (gdb_thread_options options)
{
static constexpr gdb_thread_options::string_mapping mapping[] = {
MAP_ENUM_FLAG (GDB_THREAD_OPTION_CLONE),
+ MAP_ENUM_FLAG (GDB_THREAD_OPTION_EXIT),
};
return options.to_string (mapping);
}
diff --git a/gdb/target/target.h b/gdb/target/target.h
index 2691f92..bad4daa 100644
--- a/gdb/target/target.h
+++ b/gdb/target/target.h
@@ -34,6 +34,10 @@ enum gdb_thread_option : unsigned
/* Tell the target to report TARGET_WAITKIND_THREAD_CLONED events
for the thread. */
GDB_THREAD_OPTION_CLONE = 1 << 0,
+
+ /* Tell the target to report TARGET_WAITKIND_THREAD_EXIT events for
+ the thread. */
+ GDB_THREAD_OPTION_EXIT = 1 << 1,
};
DEF_ENUM_FLAGS_TYPE (enum gdb_thread_option, gdb_thread_options);