diff options
-rw-r--r-- | gdb/linux-nat.c | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index b576ce6..75f81ed 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); } |