[19/31] Implement GDB_THREAD_OPTION_EXIT support for native Linux

Message ID 20221212203101.1034916-20-pedro@palves.net
State New
Headers
Series Step over thread clone and thread exit |

Commit Message

Pedro Alves Dec. 12, 2022, 8:30 p.m. UTC
  This implements support for the new GDB_THREAD_OPTION_EXIT thread
option for native Linux.

Change-Id: Ia69fc0b9b96f9af7de7cefc1ddb1fba9bbb0bb90
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27338
---
 gdb/linux-nat.c | 44 +++++++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 13 deletions(-)
  

Comments

Andrew Burgess June 8, 2023, 2:17 p.m. UTC | #1
Pedro Alves <pedro@palves.net> writes:

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

<sigh> maybe one day we'll be able to unify the remote native support
and GDB's in-built native support.

Like the last one, this LGTM.

Reviewed-By: Andrew Burgess <aburgess@redhat.com>

Thanks,
Andrew

>
> Change-Id: Ia69fc0b9b96f9af7de7cefc1ddb1fba9bbb0bb90
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27338
> ---
>  gdb/linux-nat.c | 44 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 31 insertions(+), 13 deletions(-)
>
> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> index b576ce60b75..75f81edf20a 100644
> --- a/gdb/linux-nat.c
> +++ b/gdb/linux-nat.c
> @@ -269,6 +269,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 = find_thread_ptid (linux_target, lp->ptid);
> +  gdb_assert (thr != nullptr);
> +
> +  return (report_thread_events
> +	  || (thr->thread_options () & GDB_THREAD_OPTION_EXIT) != 0);
> +}
> +
>  
>  /* LWP accessors.  */
>  
> @@ -2131,8 +2143,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 ());
>  
> @@ -2913,7 +2924,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 ());
> @@ -3123,10 +3134,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,
> @@ -3134,9 +3146,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
> @@ -3369,10 +3389,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
> @@ -4479,7 +4496,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);
>  }
>  
> -- 
> 2.36.0
  

Patch

diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index b576ce60b75..75f81edf20a 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -269,6 +269,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 = find_thread_ptid (linux_target, lp->ptid);
+  gdb_assert (thr != nullptr);
+
+  return (report_thread_events
+	  || (thr->thread_options () & GDB_THREAD_OPTION_EXIT) != 0);
+}
+
 
 /* LWP accessors.  */
 
@@ -2131,8 +2143,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 ());
 
@@ -2913,7 +2924,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 ());
@@ -3123,10 +3134,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,
@@ -3134,9 +3146,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
@@ -3369,10 +3389,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
@@ -4479,7 +4496,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);
 }