[8/9] Use reinsert_breakpoint for vCont;s

Message ID 1467295765-3457-9-git-send-email-yao.qi@linaro.org
State New, archived
Headers

Commit Message

Yao Qi June 30, 2016, 2:09 p.m. UTC
  V3: - install breakpoints in proceed_one_lwp, if the thread doesn't have
    reinsert breakpoints installed yet,
    - no longer stop all threads when installing breakpoints,
    - delete reinsert breakpoints when GDBserver wants to report event,

> - Also, if in all-stop mode, if gdb does:
>
> vCont;s:1;c
>
> thus setting thread 1 stepping, and all others continuing,
> and then some other thread but thread 1 hits a breakpoint,
> what is removing the reinsert breakpoint of thread 1?

if thread 1 doesn't hit the reinsert breakpoint, we don't have to
remove them, because GDB will send vCont;s:1 next time, and GDBserver
can only install reinsert breakpoints if they are not installed yet.
if thread hits the reinsert breakpoint, but the event is not reported.
It becomes pending, and GDBserver will delete the reinsert breakpoints
next time when this pending event is reported back to GDB.

V2: fix spaces in changelog entry,
    use maybe_hw_step,
    cancel step-over if signal arrives (!maybe_internal_trap),

This patch is to teach GDBserver using software single step to handle
vCont;s.  Simply speaking, if the thread's resume request is resume_step,
install reinsert breakpoint at the next pcs when GDBserver is about to
resume threads.  These reinsert breakpoints of a thread are removed,
when GDBserver gets an event from that thread and reports this event back
to GDB.

gdb/gdbserver:

2016-06-30  Yao Qi  <yao.qi@linaro.org>

	* linux-low.c (resume_stopped_resumed_lwps): If resume request
	is resume_step, call maybe_hw_step.
	(linux_wait_1): Stop all threads, remove reinsert breakpoints,
	and unstop them.
	(linux_resume_one_lwp_throw): Don't assert the thread has reinsert
	breakpoints or not.
	(proceed_one_lwp): If resume request is resume_step, install
	reinsert breakpoints and call maybe_hw_step.
---
 gdb/gdbserver/linux-low.c | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)
  

Comments

Pedro Alves July 1, 2016, 3:07 p.m. UTC | #1
On 06/30/2016 03:09 PM, Yao Qi wrote:
> V3: - install breakpoints in proceed_one_lwp, if the thread doesn't have
>     reinsert breakpoints installed yet,
>     - no longer stop all threads when installing breakpoints,
>     - delete reinsert breakpoints when GDBserver wants to report event,
> 
>> - Also, if in all-stop mode, if gdb does:
>>
>> vCont;s:1;c
>>
>> thus setting thread 1 stepping, and all others continuing,
>> and then some other thread but thread 1 hits a breakpoint,
>> what is removing the reinsert breakpoint of thread 1?
> 
> if thread 1 doesn't hit the reinsert breakpoint, we don't have to
> remove them, because GDB will send vCont;s:1 next time, and GDBserver

There's no guarantee GDB will send vCont;s:1 next time.
The user may do "continue" instead of "step".

> can only install reinsert breakpoints if they are not installed yet.

The user may even do "return + continue" or "jump", or an infcall,
all of which resume the thread at a different address from the address
the thread last stopped.  So there's no guarantee that the
reinsert breakpoint address makes any sense for the next step request,
or even that the next resume request is a step in the first place.

Basically the previous step request must be completely forgotten after
gdb has seen the thread stop.  In all-stop, gdb "sees "all threads
stopped on each and every event reported to gdb, for any thread.
A stop reply cancels any and all previous resume requests.

> if thread hits the reinsert breakpoint, but the event is not reported.
> It becomes pending, and GDBserver will delete the reinsert breakpoints
> next time when this pending event is reported back to GDB.

I don't follow.  I'm talking about the case where the thread does _not_
hit the reinsert breakpoint.  Instead some other thread hits some unrelated
event.

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index abaf288..c9bb012 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -2563,7 +2563,10 @@  resume_stopped_resumed_lwps (struct inferior_list_entry *entry)
       && !lp->status_pending_p
       && thread->last_status.kind == TARGET_WAITKIND_IGNORE)
     {
-      int step = thread->last_resume_kind == resume_step;
+      int step = 0;
+
+      if (thread->last_resume_kind == resume_step)
+	step = maybe_hw_step (thread);
 
       if (debug_threads)
 	debug_printf ("RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n",
@@ -3622,6 +3625,20 @@  linux_wait_1 (ptid_t ptid,
 
   /* Alright, we're going to report a stop.  */
 
+  /* Remove reinsert breakpoints.  */
+  if (can_software_single_step ()
+      && has_reinsert_breakpoints (current_thread))
+    {
+      /* Stop all threads before removing breakpoints out of memory,
+	 so that threads other than EVENT_CHILD won't hit the
+	 breakpoint in the staled memory.  */
+      stop_all_lwps (0, event_child);
+
+      delete_reinsert_breakpoints (current_thread);
+
+      unstop_all_lwps (0, event_child);
+    }
+
   if (!stabilizing_threads)
     {
       /* In all-stop, stop all threads.  */
@@ -4275,12 +4292,6 @@  linux_resume_one_lwp_throw (struct lwp_info *lwp,
 
       step = maybe_hw_step (thread);
     }
-  else
-    {
-      /* If the thread isn't doing step-over, there shouldn't be any
-	 reinsert breakpoints.  */
-      gdb_assert (!has_reinsert_breakpoints (thread));
-    }
 
   if (fast_tp_collecting == 1)
     {
@@ -5088,7 +5099,14 @@  proceed_one_lwp (struct inferior_list_entry *entry, void *except)
       if (debug_threads)
 	debug_printf ("   stepping LWP %ld, client wants it stepping\n",
 		      lwpid_of (thread));
-      step = 1;
+
+      /* If resume_step is requested by GDB, install reinsert
+	 breakpoints when the thread is about to be actually resumed if
+	 the reinsert breakpoints weren't removed.  */
+      if (can_software_single_step () && !has_reinsert_breakpoints (thread))
+	install_software_single_step_breakpoints (lwp);
+
+      step = maybe_hw_step (thread);
     }
   else if (lwp->bp_reinsert != 0)
     {