detach with in-line step over in progress
authorPedro Alves <pedro@palves.net>
Mon, 11 Jan 2021 23:11:57 +0000 (23:11 +0000)
committerPedro Alves <pedro@palves.net>
Wed, 3 Feb 2021 01:15:16 +0000 (01:15 +0000)
A following patch will add a testcase that has a number of threads
constantly stepping over a breakpoint, and then has GDB detach the
process.  That testcase exercises both "set displaced-stepping
on/off".  Testing with "set displaced-stepping off" reveals that GDB
does not handle the case of the user typing "detach" just while some
thread is in the middle of an in-line step over.  If that thread
belongs to the inferior that is being detached, then the step-over
never finishes, and threads of other inferiors are never re-resumed.
This fixes it.

gdb/ChangeLog:

* infrun.c (struct step_over_info): Initialize fields.
(prepare_for_detach): Handle ongoing in-line step over.

gdb/ChangeLog
gdb/infrun.c

index 4113e3a6284cc3d6e8ecba622d47e350d7294576..365d1375b9d16d36a024decd2d53531b80ce420a 100644 (file)
@@ -1,3 +1,8 @@
+2021-02-03  Pedro Alves  <pedro@palves.net>
+
+       * infrun.c (struct step_over_info): Initialize fields.
+       (prepare_for_detach): Handle ongoing in-line step over.
+
 2021-02-03  Pedro Alves  <pedro@palves.net>
 
        * linux-nat.c (linux_nat_target::detach): Remove breakpoints
index 71bf10f4c5eae5fc64fcbde41f98d20fd2e5766c..6585dddc6f8ff91c614460cb3cc6a3b889de3eb6 100644 (file)
@@ -1261,15 +1261,15 @@ struct step_over_info
      and address of the instruction the breakpoint is set at.  We'll
      skip inserting all breakpoints here.  Valid iff ASPACE is
      non-NULL.  */
-  const address_space *aspace;
-  CORE_ADDR address;
+  const address_space *aspace = nullptr;
+  CORE_ADDR address = 0;
 
   /* The instruction being stepped over triggers a nonsteppable
      watchpoint.  If true, we'll skip inserting watchpoints.  */
-  int nonsteppable_watchpoint_p;
+  int nonsteppable_watchpoint_p = 0;
 
   /* The thread's global number.  */
-  int thread;
+  int thread = -1;
 };
 
 /* The step-over info of the location that is being stepped over.
@@ -3566,6 +3566,7 @@ struct wait_one_event
 };
 
 static bool handle_one (const wait_one_event &event);
+static void restart_threads (struct thread_info *event_thread);
 
 /* Prepare and stabilize the inferior for detaching it.  E.g.,
    detaching while a thread is displaced stepping is a recipe for
@@ -3593,6 +3594,35 @@ prepare_for_detach (void)
        global_thread_step_over_chain_remove (tp);
     }
 
+  /* If we were already in the middle of an inline step-over, and the
+     thread stepping belongs to the inferior we're detaching, we need
+     to restart the threads of other inferiors.  */
+  if (step_over_info.thread != -1)
+    {
+      infrun_debug_printf ("inline step-over in-process while detaching");
+
+      thread_info *thr = find_thread_global_id (step_over_info.thread);
+      if (thr->inf == inf)
+       {
+         /* Since we removed threads of INF from the step-over chain,
+            we know this won't start a step-over for INF.  */
+         clear_step_over_info ();
+
+         if (target_is_non_stop_p ())
+           {
+             /* Start a new step-over in another thread if there's
+                one that needs it.  */
+             start_step_over ();
+
+             /* Restart all other threads (except the
+                previously-stepping thread, since that one is still
+                running).  */
+             if (!step_over_info_valid_p ())
+               restart_threads (thr);
+           }
+       }
+    }
+
   if (displaced_step_in_progress (inf))
     {
       infrun_debug_printf ("displaced-stepping in-process while detaching");
@@ -5528,6 +5558,13 @@ restart_threads (struct thread_info *event_thread)
 
   for (thread_info *tp : all_non_exited_threads ())
     {
+      if (tp->inf->detaching)
+       {
+         infrun_debug_printf ("restart threads: [%s] inferior detaching",
+                              target_pid_to_str (tp->ptid).c_str ());
+         continue;
+       }
+
       switch_to_thread_no_regs (tp);
 
       if (tp == event_thread)