From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 115767 invoked by alias); 6 Aug 2015 09:43:35 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 115752 invoked by uid 89); 6 Aug 2015 09:43:34 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.4 required=5.0 tests=AWL,BAYES_00,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 06 Aug 2015 09:43:33 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 519D1A049E; Thu, 6 Aug 2015 09:43:32 +0000 (UTC) Received: from [127.0.0.1] (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t769hU5k010148; Thu, 6 Aug 2015 05:43:31 -0400 Message-ID: <55C32C42.3020903@redhat.com> Date: Thu, 06 Aug 2015 09:43:00 -0000 From: Pedro Alves User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.5.0 MIME-Version: 1.0 To: Yao Qi CC: gdb-patches@sourceware.org Subject: [pushed]Re: [PATCH/7.10 1/2] Linux gdbserver confused when event randomization returns a process exit event References: <1438362229-27653-1-git-send-email-palves@redhat.com> <1438362229-27653-2-git-send-email-palves@redhat.com> <86io8weize.fsf@gmail.com> In-Reply-To: <86io8weize.fsf@gmail.com> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-SW-Source: 2015-08/txt/msg00137.txt.bz2 On 08/03/2015 11:58 AM, Yao Qi wrote: > Pedro Alves writes: > >> @@ -3128,7 +3116,7 @@ linux_wait_1 (ptid_t ptid, >> || (gdb_breakpoint_here (event_child->stop_pc) >> && gdb_condition_true_at_breakpoint (event_child->stop_pc) >> && gdb_no_commands_at_breakpoint (event_child->stop_pc)) >> - || extended_event_reported (&event_child->waitstatus)); >> + || event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE); >> >> run_breakpoint_commands (event_child->stop_pc); >> >> @@ -3150,9 +3138,11 @@ linux_wait_1 (ptid_t ptid, >> paddress (event_child->stop_pc), >> paddress (event_child->step_range_start), >> paddress (event_child->step_range_end)); >> - if (extended_event_reported (&event_child->waitstatus)) >> + if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE) >> { >> - char *str = target_waitstatus_to_string (ourstatus); >> + char *str; >> + >> + str = target_waitstatus_to_string (&event_child->waitstatus); >> debug_printf ("LWP %ld: extended event with waitstatus %s\n", >> lwpid_of (get_lwp_thread (event_child)), str); >> xfree (str); > > Looks this code is dead code even without your patch. This code is > guarded by "if (!report_to_gdb)", but if report_to_gdb is false, > "(event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE)" is false too. That bit went in separately, so here's the updated patch that I pushed. I'll push it to 7.10 too in a bit. --- >From 00db26facc14ac830adef704bba9b24d0d366ddf Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Thu, 6 Aug 2015 10:30:17 +0100 Subject: [PATCH 2/3] Linux gdbserver confused when event randomization picks process exit event The tail end of linux_wait_1 isn't expecting that the select_event_lwp machinery can pick a whole-process exit event to report to GDB. When that happens, both gdb and gdbserver end up quite confused: ... (gdb) [Thread 24971.24971] #1 stopped. 0x0000003615a011f0 in ?? () c& Continuing. (gdb) [New Thread 24971.24981] [New Thread 24983.24983] [New Thread 24971.24982] [Thread 24983.24983] #3 stopped. 0x0000003615ebc7cc in __libc_fork () at ../nptl/sysdeps/unix/sysv/linux/fork.c:130 130 pid = ARCH_FORK (); [New Thread 24984.24984] Error in re-setting breakpoint -16: PC register is not available Error in re-setting breakpoint -17: PC register is not available Error in re-setting breakpoint -18: PC register is not available Error in re-setting breakpoint -19: PC register is not available Error in re-setting breakpoint -24: PC register is not available Error in re-setting breakpoint -25: PC register is not available Error in re-setting breakpoint -26: PC register is not available Error in re-setting breakpoint -27: PC register is not available Error in re-setting breakpoint -28: PC register is not available Error in re-setting breakpoint -29: PC register is not available Error in re-setting breakpoint -30: PC register is not available PC register is not available (gdb) gdb/gdbserver/ChangeLog: 2015-08-06 Pedro Alves * linux-low.c (add_lwp): Set waitstatus to TARGET_WAITKIND_IGNORE. (linux_thread_alive): Use lwp_is_marked_dead. (extended_event_reported): Delete. (linux_wait_1): Check if waitstatus is TARGET_WAITKIND_IGNORE instead of extended_event_reported. (mark_lwp_dead): Don't set the 'dead' flag. Store the waitstatus as well. (lwp_is_marked_dead): New function. (lwp_running): Use lwp_is_marked_dead. * linux-low.h: Delete 'dead' field, and update 'waitstatus's comment. --- gdb/gdbserver/ChangeLog | 14 +++++++++++ gdb/gdbserver/linux-low.c | 64 ++++++++++++++++++++++++++--------------------- gdb/gdbserver/linux-low.h | 11 +++----- 3 files changed, 54 insertions(+), 35 deletions(-) diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index eb1101c..77b4330 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,5 +1,19 @@ 2015-08-06 Pedro Alves + * linux-low.c (add_lwp): Set waitstatus to TARGET_WAITKIND_IGNORE. + (linux_thread_alive): Use lwp_is_marked_dead. + (extended_event_reported): Delete. + (linux_wait_1): Check if waitstatus is TARGET_WAITKIND_IGNORE + instead of extended_event_reported. + (mark_lwp_dead): Don't set the 'dead' flag. Store the waitstatus + as well. + (lwp_is_marked_dead): New function. + (lwp_running): Use lwp_is_marked_dead. + * linux-low.h: Delete 'dead' field, and update 'waitstatus's + comment. + +2015-08-06 Pedro Alves + * linux-low.c (linux_wait_1): Move fork event output out of the !report_to_gdb check. Pass event_child->waitstatus to target_waitstatus_to_string instead of ourstatus. diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 76b212d..6a7182a 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -267,6 +267,7 @@ static int linux_wait_for_event (ptid_t ptid, int *wstat, int options); static struct lwp_info *add_lwp (ptid_t ptid); static int linux_stopped_by_watchpoint (void); static void mark_lwp_dead (struct lwp_info *lwp, int wstat); +static int lwp_is_marked_dead (struct lwp_info *lwp); static void proceed_all_lwps (void); static int finish_step_over (struct lwp_info *lwp); static int kill_lwp (unsigned long lwpid, int signo); @@ -746,8 +747,9 @@ add_lwp (ptid_t ptid) { struct lwp_info *lwp; - lwp = (struct lwp_info *) xmalloc (sizeof (*lwp)); - memset (lwp, 0, sizeof (*lwp)); + lwp = (struct lwp_info *) xcalloc (1, sizeof (*lwp)); + + lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE; if (the_low_target.new_thread != NULL) the_low_target.new_thread (lwp); @@ -1396,7 +1398,7 @@ linux_thread_alive (ptid_t ptid) exited but we still haven't been able to report it to GDB, we'll hold on to the last lwp of the dead process. */ if (lwp != NULL) - return !lwp->dead; + return !lwp_is_marked_dead (lwp); else return 0; } @@ -2750,20 +2752,6 @@ ignore_event (struct target_waitstatus *ourstatus) return null_ptid; } -/* Return non-zero if WAITSTATUS reflects an extended linux - event. Otherwise, return zero. */ - -static int -extended_event_reported (const struct target_waitstatus *waitstatus) -{ - if (waitstatus == NULL) - return 0; - - return (waitstatus->kind == TARGET_WAITKIND_FORKED - || waitstatus->kind == TARGET_WAITKIND_VFORKED - || waitstatus->kind == TARGET_WAITKIND_VFORK_DONE); -} - /* Wait for process, returns status. */ static ptid_t @@ -3131,7 +3119,7 @@ linux_wait_1 (ptid_t ptid, || (gdb_breakpoint_here (event_child->stop_pc) && gdb_condition_true_at_breakpoint (event_child->stop_pc) && gdb_no_commands_at_breakpoint (event_child->stop_pc)) - || extended_event_reported (&event_child->waitstatus)); + || event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE); run_breakpoint_commands (event_child->stop_pc); @@ -3183,7 +3171,7 @@ linux_wait_1 (ptid_t ptid, if (debug_threads) { - if (extended_event_reported (&event_child->waitstatus)) + if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE) { char *str; @@ -3271,12 +3259,11 @@ linux_wait_1 (ptid_t ptid, unstop_all_lwps (1, event_child); } - if (extended_event_reported (&event_child->waitstatus)) + if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE) { - /* If the reported event is a fork, vfork or exec, let GDB know. */ - ourstatus->kind = event_child->waitstatus.kind; - ourstatus->value = event_child->waitstatus.value; - + /* If the reported event is an exit, fork, vfork or exec, let + GDB know. */ + *ourstatus = event_child->waitstatus; /* Clear the event lwp's waitstatus since we handled it already. */ event_child->waitstatus.kind = TARGET_WAITKIND_IGNORE; } @@ -3484,13 +3471,23 @@ suspend_and_send_sigstop_callback (struct inferior_list_entry *entry, static void mark_lwp_dead (struct lwp_info *lwp, int wstat) { - /* It's dead, really. */ - lwp->dead = 1; - /* Store the exit status for later. */ lwp->status_pending_p = 1; lwp->status_pending = wstat; + /* Store in waitstatus as well, as there's nothing else to process + for this event. */ + if (WIFEXITED (wstat)) + { + lwp->waitstatus.kind = TARGET_WAITKIND_EXITED; + lwp->waitstatus.value.integer = WEXITSTATUS (wstat); + } + else if (WIFSIGNALED (wstat)) + { + lwp->waitstatus.kind = TARGET_WAITKIND_SIGNALLED; + lwp->waitstatus.value.sig = gdb_signal_from_host (WTERMSIG (wstat)); + } + /* Prevent trying to stop it. */ lwp->stopped = 1; @@ -3498,6 +3495,17 @@ mark_lwp_dead (struct lwp_info *lwp, int wstat) lwp->stop_expected = 0; } +/* Return true if LWP has exited already, and has a pending exit event + to report to GDB. */ + +static int +lwp_is_marked_dead (struct lwp_info *lwp) +{ + return (lwp->status_pending_p + && (WIFEXITED (lwp->status_pending) + || WIFSIGNALED (lwp->status_pending))); +} + /* Wait for all children to stop for the SIGSTOPs we just queued. */ static void @@ -3614,7 +3622,7 @@ lwp_running (struct inferior_list_entry *entry, void *data) struct thread_info *thread = (struct thread_info *) entry; struct lwp_info *lwp = get_thread_lwp (thread); - if (lwp->dead) + if (lwp_is_marked_dead (lwp)) return 0; if (lwp->stopped) return 0; diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index 24fb015..f8f6e78 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -261,16 +261,13 @@ struct lwp_info event already received in a wait()). */ int stopped; - /* If this flag is set, the lwp is known to be dead already (exit - event already received in a wait(), and is cached in - status_pending). */ - int dead; - /* When stopped is set, the last wait status recorded for this lwp. */ int last_status; - /* This is used to store extended ptrace event information until - it is reported to GDB. */ + /* If WAITSTATUS->KIND != TARGET_WAITKIND_IGNORE, the waitstatus for + this LWP's last event, to pass to GDB without any further + processing. This is used to store extended ptrace event + information or exit status until it can be reported to GDB. */ struct target_waitstatus waitstatus; /* When stopped is set, this is where the lwp last stopped, with -- 1.9.3