From patchwork Sat Feb 24 00:09:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 26042 Received: (qmail 6908 invoked by alias); 24 Feb 2018 00:10:33 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 6897 invoked by uid 89); 24 Feb 2018 00:10:32 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS, SPF_SOFTFAIL autolearn=ham version=3.3.2 spammy=retrieved, 3s, wish X-HELO: mail.baldwin.cx Received: from bigwig.baldwin.cx (HELO mail.baldwin.cx) (96.47.65.170) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 24 Feb 2018 00:10:30 +0000 Received: from ralph.baldwin.cx.com (ralph.baldwin.cx [66.234.199.215]) by mail.baldwin.cx (Postfix) with ESMTPSA id CA9B110A87D for ; Fri, 23 Feb 2018 19:10:27 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH] Workaround a FreeBSD ptrace() bug with clearing thread events. Date: Fri, 23 Feb 2018 16:09:35 -0800 Message-Id: <20180224000935.43344-1-jhb@FreeBSD.org> X-IsSubscribed: yes When multiple threads within a process wish to report STOPPED events from wait(), the kernel picks one thread event as the thread event to report. The chosen thread event is retrieved via PT_LWPINFO by passing the process ID as the request pid. If multiple events are pending, then the subsequent wait() after resuming a process will report another STOPPED event after resuming the process to handle the next thread event and so on. A single thread event is cleared as a side effect of resuming the process with PT_CONTINUE, PT_STEP, etc. In older kernels, however, the request pid was used to select which thread's event was cleared rather than always clearing the event that was just reported. To avoid clearing the event of the wrong LWP, always pass the process ID instead of an LWP ID to PT_CONTINUE or PT_SYSCALL. In the case of stepping, the process ID cannot be used with PT_STEP since it would step the thread that reported an event which may not be the thread indicated by PTID. For stepping, use PT_SETSTEP to enable stepping on the desired thread before resuming the process via PT_CONTINUE instead of using PT_STEP. This manifested as a failure in the gdb.threads/continue-pending-status.exp test. Specifically, if thread 2 reported a breakpoint and the test thus switched to thread 3 before continuing, thread 3's event (if any) was discarded and thread 2's breakpoint remained pending and was reported a second time as a duplicate event. As a result, the PC was decremented twice for the same breakpoint resulting in an illegal instruction fault on x86. gdb/ChangeLog: * fbsd-nat.c (fbsd_resume): Use PT_SETSTEP for stepping and a wildcard process pid for super_resume for kernels with a specific bug. --- gdb/ChangeLog | 6 ++++++ gdb/fbsd-nat.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d661310b07..3db2f544bf 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2017-09-22 John Baldwin + + * fbsd-nat.c (fbsd_resume): Use PT_SETSTEP for stepping and a + wildcard process pid for super_resume for kernels with a + specific bug. + 2017-09-22 John Baldwin * fbsd-nat.c: Include "inf-ptrace.h". diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index d44950618c..9c87bfed33 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -1163,6 +1163,39 @@ fbsd_resume (struct target_ops *ops, } ptid = inferior_ptid; } + +#if __FreeBSD_version < 1200052 + /* + * When multiple threads within a process wish to report STOPPED + * events from wait(), the kernel picks one thread event as the + * thread event to report. The chosen thread event is retrieved via + * PT_LWPINFO by passing the process ID as the request pid. If + * multiple events are pending, then the subsequent wait() after + * resuming a process will report another STOPPED event after + * resuming the process to handle the next thread event and so on. + * + * A single thread event is cleared as a side effect of resuming the + * process with PT_CONTINUE, PT_STEP, etc. In older kernels, + * however, the request pid was used to select which thread's event + * was cleared rather than always clearing the event that was just + * reported. To avoid clearing the event of the wrong LWP, always + * pass the process ID instead of an LWP ID to PT_CONTINUE or + * PT_SYSCALL. + * + * In the case of stepping, the process ID cannot be used with + * PT_STEP since it would step the thread that reported an event + * which may not be the thread indicated by PTID. For stepping, use + * PT_SETSTEP to enable stepping on the desired thread before + * resuming the process via PT_CONTINUE instead of using PT_STEP. + */ + if (step) + { + if (ptrace (PT_SETSTEP, get_ptrace_pid (ptid), NULL, 0) == -1) + perror_with_name (("ptrace")); + step = 0; + } + ptid = ptid_t (ptid.pid ()); +#endif super_resume (ops, ptid, step, signo); }