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 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. */
@ -2148,8 +2160,7 @@ wait_lwp (struct lwp_info *lp)
/* Check if the thread has exited. */
if (WIFEXITED (status) || WIFSIGNALED (status))
{
if (report_thread_events
|| lp->ptid.pid () == lp->ptid.lwp ())
if (report_exit_events_for (lp) || is_leader (lp))
{
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. */
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.",
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
event. This decides whether to report the event to GDB as a
process exit event, a thread exit event, or to suppress the
event. */
/* Convenience function that is called when we're about to return an
event to the core. If the event is an exit or signalled event,
then this decides whether to report it as process-wide event, as a
thread exit event, or to suppress it. All other event kinds are
passed through unmodified. */
static ptid_t
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;
/* 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 (report_thread_events)
if (report_exit_events_for (event_child))
{
ourstatus->set_thread_exited (0);
/* 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
lp->core = linux_common_core_of_thread (lp->ptid);
if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
return filter_exit_event (lp, ourstatus);
return lp->ptid;
return filter_exit_event (lp, ourstatus);
}
/* Resume LWPs that are currently stopped without any pending status
@ -4513,7 +4530,8 @@ linux_nat_target::thread_events (int enable)
bool
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);
}