Delete reinsert breakpoints from forked child
authorYao Qi <yao.qi@linaro.org>
Fri, 17 Jun 2016 09:25:13 +0000 (10:25 +0100)
committerYao Qi <yao.qi@linaro.org>
Fri, 17 Jun 2016 09:38:55 +0000 (10:38 +0100)
When a thread is stepping over a syscall instruction with software
single step, GDBserver inserts reinsert breakpoints at the next pcs.
If the syscall call is fork, the forked child has reinsert breakpoint
in its space, and GDBserver clones parent's breakpoint list to child's.
When GDBserver resumes the child, its bp_reinsert is zero, but has
reinsert breakpoints, so the following assert is triggered if I apply
the patch extending step-over-syscall.exp.

gdb/gdbserver/linux-low.c:4292: A problem internal to GDBserver has been detected.^M
void linux_resume_one_lwp_throw(lwp_info*, int, int, siginfo_t*): Assertion `!has_reinsert_breakpoints (proc)' failed.

gdb/gdbserver:

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.

gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c

index fd70f59c94364aab4a05410f252185bd1f4a6cdc..734d70dd656177f1eb5e1ce68b12017508b1c556 100644 (file)
@@ -1,3 +1,8 @@
+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.
+
 2016-06-17  Yao Qi  <yao.qi@linaro.org>
 
        * linux-low.c (unsuspend_all_lwps): Declare.
index 95104d264343b50d835ce9bccd4bcae76e669903..3f2d08eea5accbc7e4f84a4219ca208df3dcc658 100644 (file)
@@ -569,6 +569,27 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat)
          event_lwp->status_pending_p = 1;
          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.  */
+         if (event_lwp->bp_reinsert != 0
+             && can_software_single_step ()
+             && event == PTRACE_EVENT_FORK)
+           {
+             struct thread_info *saved_thread = current_thread;
+
+             /* The child process is forked and stopped, so it is safe
+                to access its memory without stopping all other threads
+                from other processes.  */
+             current_thread = child_thr;
+             delete_reinsert_breakpoints ();
+             current_thread = saved_thread;
+
+             gdb_assert (has_reinsert_breakpoints (parent_proc));
+             gdb_assert (!has_reinsert_breakpoints (child_proc));
+           }
+
          /* Report the event.  */
          return 0;
        }