aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/gdbserver/ChangeLog11
-rw-r--r--gdb/gdbserver/linux-low.c38
-rw-r--r--gdb/gdbserver/mem-break.c38
-rw-r--r--gdb/gdbserver/mem-break.h9
4 files changed, 91 insertions, 5 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 734d70d..6983e19 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,16 @@
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.
+
+2016-06-17 Yao Qi <yao.qi@linaro.org>
+
* linux-low.c (handle_extended_wait): If the parent is doing
step-over, remove the reinsert breakpoints from the forked child.
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). */