diff options
-rw-r--r-- | gdb/gdbserver/ChangeLog | 11 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.c | 38 | ||||
-rw-r--r-- | gdb/gdbserver/mem-break.c | 38 | ||||
-rw-r--r-- | gdb/gdbserver/mem-break.h | 9 |
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). */ |