Implement GDB_THREAD_OPTION_EXIT support for native Linux

This implements support for the new GDB_THREAD_OPTION_EXIT thread
option for native Linux.

Reviewed-By: Andrew Burgess <aburgess@redhat.com>
Change-Id: Ia69fc0b9b96f9af7de7cefc1ddb1fba9bbb0bb90
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27338
This commit is contained in:
Pedro Alves
2022-03-21 19:09:13 +00:00
parent 4898949800
commit a51e14efe2

View File

@@ -268,6 +268,18 @@ pending_status_str (lwp_info *lp)
return status_to_str (lp->status); return status_to_str (lp->status);
} }
/* Return true if we should report exit events for LP. */
static bool
report_exit_events_for (lwp_info *lp)
{
thread_info *thr = linux_target->find_thread (lp->ptid);
gdb_assert (thr != nullptr);
return (report_thread_events
|| (thr->thread_options () & GDB_THREAD_OPTION_EXIT) != 0);
}
/* LWP accessors. */ /* LWP accessors. */
@@ -2148,8 +2160,7 @@ wait_lwp (struct lwp_info *lp)
/* Check if the thread has exited. */ /* Check if the thread has exited. */
if (WIFEXITED (status) || WIFSIGNALED (status)) if (WIFEXITED (status) || WIFSIGNALED (status))
{ {
if (report_thread_events if (report_exit_events_for (lp) || is_leader (lp))
|| lp->ptid.pid () == lp->ptid.lwp ())
{ {
linux_nat_debug_printf ("LWP %d exited.", lp->ptid.pid ()); linux_nat_debug_printf ("LWP %d exited.", lp->ptid.pid ());
@@ -2932,7 +2943,7 @@ linux_nat_filter_event (int lwpid, int status)
/* Check if the thread has exited. */ /* Check if the thread has exited. */
if (WIFEXITED (status) || WIFSIGNALED (status)) if (WIFEXITED (status) || WIFSIGNALED (status))
{ {
if (!report_thread_events && !is_leader (lp)) if (!report_exit_events_for (lp) && !is_leader (lp))
{ {
linux_nat_debug_printf ("%s exited.", linux_nat_debug_printf ("%s exited.",
lp->ptid.to_string ().c_str ()); lp->ptid.to_string ().c_str ());
@@ -3142,10 +3153,11 @@ check_zombie_leaders (void)
} }
} }
/* Convenience function that is called when the kernel reports an exit /* Convenience function that is called when we're about to return an
event. This decides whether to report the event to GDB as a event to the core. If the event is an exit or signalled event,
process exit event, a thread exit event, or to suppress the then this decides whether to report it as process-wide event, as a
event. */ thread exit event, or to suppress it. All other event kinds are
passed through unmodified. */
static ptid_t static ptid_t
filter_exit_event (struct lwp_info *event_child, filter_exit_event (struct lwp_info *event_child,
@@ -3153,9 +3165,17 @@ filter_exit_event (struct lwp_info *event_child,
{ {
ptid_t ptid = event_child->ptid; ptid_t ptid = event_child->ptid;
/* Note we must filter TARGET_WAITKIND_SIGNALLED as well, otherwise
if a non-leader thread exits with a signal, we'd report it to the
core which would interpret it as the whole-process exiting.
There is no TARGET_WAITKIND_THREAD_SIGNALLED event kind. */
if (ourstatus->kind () != TARGET_WAITKIND_EXITED
&& ourstatus->kind () != TARGET_WAITKIND_SIGNALLED)
return ptid;
if (!is_leader (event_child)) if (!is_leader (event_child))
{ {
if (report_thread_events) if (report_exit_events_for (event_child))
{ {
ourstatus->set_thread_exited (0); ourstatus->set_thread_exited (0);
/* Delete lwp, but not thread_info, infrun will need it to /* Delete lwp, but not thread_info, infrun will need it to
@@ -3388,10 +3408,7 @@ linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
else else
lp->core = linux_common_core_of_thread (lp->ptid); lp->core = linux_common_core_of_thread (lp->ptid);
if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
return filter_exit_event (lp, ourstatus); return filter_exit_event (lp, ourstatus);
return lp->ptid;
} }
/* Resume LWPs that are currently stopped without any pending status /* Resume LWPs that are currently stopped without any pending status
@@ -4513,7 +4530,8 @@ linux_nat_target::thread_events (int enable)
bool bool
linux_nat_target::supports_set_thread_options (gdb_thread_options options) linux_nat_target::supports_set_thread_options (gdb_thread_options options)
{ {
constexpr gdb_thread_options supported_options = GDB_THREAD_OPTION_CLONE; constexpr gdb_thread_options supported_options
= GDB_THREAD_OPTION_CLONE | GDB_THREAD_OPTION_EXIT;
return ((options & supported_options) == options); return ((options & supported_options) == options);
} }