From patchwork Thu Jun 2 09:30:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yao Qi X-Patchwork-Id: 12700 Received: (qmail 82489 invoked by alias); 2 Jun 2016 09:31:08 -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 82223 invoked by uid 89); 2 Jun 2016 09:31:06 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 spammy=visible X-HELO: mail-pf0-f193.google.com Received: from mail-pf0-f193.google.com (HELO mail-pf0-f193.google.com) (209.85.192.193) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Thu, 02 Jun 2016 09:31:01 +0000 Received: by mail-pf0-f193.google.com with SMTP id b124so7383985pfb.0 for ; Thu, 02 Jun 2016 02:31:01 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=URItijFIK4iqH3LU9OF9tLYEmpfn2ViHaTPkk+WAv88=; b=GOYrNHtBNinlSSsQqUeU1Cy1MGL/nj5fsB8/v2BMaih71xJh6PS+1T90eTFPCp1Dit Cj3oDdsVZz8nOUg/K7hidD5OShf53KQWRm/KwA3rPnldrs9Vg9ldHVHhtZvZhfkTpgC2 mlxehokm9iptcymqN0he12s7ma8yODL2lwwvOsHaAV7N8WTkiDHQyh7gTLs0qJdU979Z hXE9+x2kdosE9REhXBIkIh39vYe3NVHcnmPibczyilsWvaLEHFxNXeyt3h4F7JkFsR/o wP9nKefUHV1JxMF2O3lOaqFyEVO70B2PLapL9rDnew7BIrHUZ/gT9TCegQ+OXuI1Wua6 nCUQ== X-Gm-Message-State: ALyK8tLo1lA+2kk0z5LDbF07xAgq7t+V5Z/FIScdIBlJoVS/CZ+03A36laeCEw8VsowyXg== X-Received: by 10.98.92.71 with SMTP id q68mr2687154pfb.138.1464859859613; Thu, 02 Jun 2016 02:30:59 -0700 (PDT) Received: from E107787-LIN.cambridge.arm.com (gcc113.osuosl.org. [140.211.9.71]) by smtp.gmail.com with ESMTPSA id hw10sm68656218pac.15.2016.06.02.02.30.58 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 02 Jun 2016 02:30:59 -0700 (PDT) From: Yao Qi X-Google-Original-From: Yao Qi To: gdb-patches@sourceware.org Subject: [PATCH 05/12] Handle reinsert breakpoints for vforked child Date: Thu, 2 Jun 2016 10:30:39 +0100 Message-Id: <1464859846-15619-6-git-send-email-yao.qi@linaro.org> In-Reply-To: <1464859846-15619-1-git-send-email-yao.qi@linaro.org> References: <1464859846-15619-1-git-send-email-yao.qi@linaro.org> X-IsSubscribed: yes When a thread is doing step-over with reinsert breakpoint, and the instruction executed is a syscall doing vfork, both parent and child share the memory, so the reinsert breakpoint in the space is visible to both of them. Also, removing the reinsert breakpoints from the child will effectively remove them from the parent. We should carefully manipulate reinsert breakpoints for both processes. What we are doing here is that - uninsert reinsert breakpoints from the parent before cloning the breakpoint list. We use "uninsert" instead of "remove", because we need to "reinsert" them back after vfork is done. In fact, "uninsert" removes them from both child and parent process space. - reinsert breakpoints in parent process are still copied to child's breakpoint list, - remove them from child's breakpoint list as what we did for fork, at this point, reinsert breakpoints are removed from the child and the parent, but they are still tracked by the parent's breakpoint list, - once vfork is done, "reinsert" them back to the parent, gdb/gdbserver: 2016-05-26 Yao Qi * linux-low.c (handle_extended_wait): Call uninsert_reinsert_breakpoints for the parent process. Remove reinsert breakpoints from the child process. Reinsert them to the parent process when vfork is done. * mem-break.c (uninsert_reinsert_breakpoints): New function. (reinsert_reinsert_breakpoints): New function. * mem-break.h (uninsert_reinsert_breakpoints): Declare (reinsert_reinsert_breakpoints): Declare. gdb/testsuite: 2016-05-26 Yao Qi * gdb.base/step-over-fork-1.exp: Extend the test for vfork. --- gdb/gdbserver/linux-low.c | 38 +++++++++++++++++++++++++---- gdb/gdbserver/mem-break.c | 38 +++++++++++++++++++++++++++++ gdb/gdbserver/mem-break.h | 9 +++++++ gdb/testsuite/gdb.base/step-over-fork-1.exp | 2 +- 4 files changed, 81 insertions(+), 6 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 3f2d08e..dd92e78 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -543,6 +543,22 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) parent_proc = get_thread_process (event_thr); child_proc->attached = parent_proc->attached; + + if (event_lwp->bp_reinsert != 0 + && can_software_single_step () + && event == PTRACE_EVENT_VFORK) + { + struct thread_info *saved_thread = current_thread; + + current_thread = event_thr; + /* If we leave reinsert breakpoints there, child will + hit it, so uninsert reinsert breakpoints from parent + (and child). Once vfork child is done, reinsert + them back to parent. */ + uninsert_reinsert_breakpoints (); + current_thread = saved_thread; + } + clone_all_breakpoints (&child_proc->breakpoints, &child_proc->raw_breakpoints, parent_proc->breakpoints); @@ -570,12 +586,12 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) event_lwp->status_pending = wstat; /* If the parent thread is doing step-over with reinsert - breakpoints, the reinsert breakpoints are still in forked - child's process space and cloned to its breakpoint list - from the parent's. Remove them from the child process. */ + breakpoints, the list of reinsert breakpoints are cloned + from the parent's. Remove them from the child process. + In case of vfork, we'll reinsert them back once vforked + child is done. */ if (event_lwp->bp_reinsert != 0 - && can_software_single_step () - && event == PTRACE_EVENT_FORK) + && can_software_single_step ()) { struct thread_info *saved_thread = current_thread; @@ -639,6 +655,18 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) { event_lwp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE; + if (event_lwp->bp_reinsert != 0 && can_software_single_step ()) + { + struct thread_info *saved_thread = current_thread; + struct process_info *proc = get_thread_process (event_thr); + + current_thread = event_thr; + reinsert_reinsert_breakpoints (); + current_thread = saved_thread; + + gdb_assert (has_reinsert_breakpoints (proc)); + } + /* Report the event. */ return 0; } diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c index c27e803..5c73326 100644 --- a/gdb/gdbserver/mem-break.c +++ b/gdb/gdbserver/mem-break.c @@ -1509,6 +1509,26 @@ uninsert_all_breakpoints (void) uninsert_raw_breakpoint (bp); } +void +uninsert_reinsert_breakpoints (void) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp; + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + { + if (bp->type == reinsert_breakpoint) + { + gdb_assert (bp->raw->inserted > 0); + + /* Only uninsert the raw breakpoint if it only belongs to a + reinsert breakpoint. */ + if (bp->raw->refcount == 1) + uninsert_raw_breakpoint (bp->raw); + } + } +} + static void reinsert_raw_breakpoint (struct raw_breakpoint *bp) { @@ -1589,6 +1609,24 @@ reinsert_all_breakpoints (void) } void +reinsert_reinsert_breakpoints (void) +{ + struct process_info *proc = current_process (); + struct breakpoint *bp; + + for (bp = proc->breakpoints; bp != NULL; bp = bp->next) + { + if (bp->type == reinsert_breakpoint) + { + gdb_assert (bp->raw->inserted > 0); + + if (bp->raw->refcount == 1) + reinsert_raw_breakpoint (bp->raw); + } + } +} + +void check_breakpoints (CORE_ADDR stop_pc) { struct process_info *proc = current_process (); diff --git a/gdb/gdbserver/mem-break.h b/gdb/gdbserver/mem-break.h index b84dc1e..6a06c0c 100644 --- a/gdb/gdbserver/mem-break.h +++ b/gdb/gdbserver/mem-break.h @@ -158,6 +158,15 @@ void set_reinsert_breakpoint (CORE_ADDR stop_at); void delete_reinsert_breakpoints (void); +/* Reinsert all reinsert breakpoints of the current process. */ + +void reinsert_reinsert_breakpoints (void); + +/* Uninsert all reinsert breakpoints of the current process. This + still leaves the reinsert breakpoints in the table. */ + +void uninsert_reinsert_breakpoints (void); + /* Reinsert breakpoints at WHERE (and change their status to inserted). */ diff --git a/gdb/testsuite/gdb.base/step-over-fork-1.exp b/gdb/testsuite/gdb.base/step-over-fork-1.exp index 4a34e61..6791c8f 100644 --- a/gdb/testsuite/gdb.base/step-over-fork-1.exp +++ b/gdb/testsuite/gdb.base/step-over-fork-1.exp @@ -101,6 +101,6 @@ proc test { syscall } { gdb_exit } -foreach_with_prefix syscall { "fork" } { +foreach_with_prefix syscall { "fork" "vfork" } { test $syscall }