diff options
author | Yao Qi <yao.qi@linaro.org> | 2016-06-17 10:25:13 +0100 |
---|---|---|
committer | Yao Qi <yao.qi@linaro.org> | 2016-06-17 10:38:55 +0100 |
commit | 2e7b624b851c34f6bc2ab75fcbc94db75f72eb3a (patch) | |
tree | b0842176277f961eb6d56c90ab88b28f8cadd033 /gdb/gdbserver/linux-low.c | |
parent | 8a81c5d7a7cc3ec4d60032d2a911d2f6c3eb8328 (diff) | |
download | gdb-2e7b624b851c34f6bc2ab75fcbc94db75f72eb3a.zip gdb-2e7b624b851c34f6bc2ab75fcbc94db75f72eb3a.tar.gz gdb-2e7b624b851c34f6bc2ab75fcbc94db75f72eb3a.tar.bz2 |
Handle reinsert breakpoints for vforked child
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-06-17 Yao Qi <yao.qi@linaro.org>
* 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.
Diffstat (limited to 'gdb/gdbserver/linux-low.c')
-rw-r--r-- | gdb/gdbserver/linux-low.c | 38 |
1 files changed, 33 insertions, 5 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; } |