[binutils-gdb] Windows gdb: all-stop, interrupt with "stopped" instead of SIGTRAP

Pedro Alves via Gdb-cvs <[email protected]>
Newsgroups gmane.comp.gdb.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4123b501791a5e1d991a880dffa2330f413f6917

commit 4123b501791a5e1d991a880dffa2330f413f6917
Author: Pedro Alves <[email protected]>
Date:   Fri May 5 15:51:31 2023 +0100

    Windows gdb: all-stop, interrupt with "stopped" instead of SIGTRAP
    
    Currently, "interrupt" uses DebugBreakProcess (or equivalent), which
    injects a new thread in the inferior that executes an int3 instruction
    (on x86), which raises a SIGTRAP.  With the target backend in non-stop
    mode, its easy to avoid all that and make interrupt in all-stop just
    suspend a pre-existing thread and report "stopped", like "set non-stop
    on" does (via target_stop).
    
    E.g., before:
    
     (gdb) c&
     Continuing.
     ...
     (gdb) info threads
       Id   Target Id          Frame
     * 1    Thread 1180.0x1374 (running)
       2    Thread 1180.0xc3c  (running)
       3    Thread 1180.0x6ec  (running)
       5    Thread 1180.0x1378 (running)
     (gdb)
     ...
     [New Thread 1180.0xc70]
     [Thread 1180.0x1378 exited with code 0]
     [Thread 1180.0xc70 exited with code 0]
     [New Thread 1180.0xdc0]
     ...
     interrupt
     (gdb) [New Thread 1180.0x1010]
    
     Thread 8 received signal SIGTRAP, Trace/breakpoint trap.
     [Switching to Thread 1180.0x1010]
     0x00007ffa57490b71 in ntdll!DbgBreakPoint () from C:\Windows\SYSTEM32\ntdll.dll
     info threads
       Id   Target Id          Frame
       1    Thread 1180.0x1374 0x00007ffa5748d6e4 in ntdll!ZwDelayExecution () from C:\Windows\SYSTEM32\ntdll.dll
       2    Thread 1180.0xc3c  0x00007ffa57490ad4 in ntdll!ZwWaitForWorkViaWorkerFactory () from C:\Windows\SYSTEM32\ntdll.dll
       3    Thread 1180.0x6ec  0x00007ffa5748d6e4 in ntdll!ZwDelayExecution () from C:\Windows\SYSTEM32\ntdll.dll
       7    Thread 1180.0xdc0  0x00007ffa5748d6e4 in ntdll!ZwDelayExecution () from C:\Windows\SYSTEM32\ntdll.dll
     * 8    Thread 1180.0x1010 0x00007ffa57490b71 in ntdll!DbgBreakPoint () from C:\Windows\SYSTEM32\ntdll.dll
     (gdb)
    
    After:
    
     (gdb) info threads
       Id   Target Id          Frame
     * 1    Thread 5912.0x394  (running)
       2    Thread 5912.0x608  (running)
       3    Thread 5912.0x1704 (running)
       10   Thread 5912.0x870  (running)
     (gdb)
     ...
     [Thread 5912.0x870 exited with code 0]
     ...
     (gdb) interrupt
     (gdb)
     Thread 1 stopped.
     0x00007ffa5748d6e4 in ntdll!ZwDelayExecution () from C:\Windows\SYSTEM32\ntdll.dll
     info threads
       Id   Target Id          Frame
     * 1    Thread 5912.0x394  0x00007ffa5748d6e4 in ntdll!ZwDelayExecution () from C:\Windows\SYSTEM32\ntdll.dll
       2    Thread 5912.0x608  0x00007ffa57490ad4 in ntdll!ZwWaitForWorkViaWorkerFactory () from C:\Windows\SYSTEM32\ntdll.dll
       3    Thread 5912.0x1704 0x00007ffa5748d6e4 in ntdll!ZwDelayExecution () from C:\Windows\SYSTEM32\ntdll.dll
       8    Thread 5912.0x1200 0x00007ffa5748d6e4 in ntdll!ZwDelayExecution () from C:\Windows\SYSTEM32\ntdll.dll
     (gdb)
    
    Approved-By: Tom Tromey <[email protected]>
    Change-Id: I569fc69392ce9a070a2ebe1003388b7386412b14
    commit-id: 8f6b76d2

Diff:
---
 gdb/windows-nat.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++---------
 gdb/windows-nat.h |  5 +++-
 2 files changed, 61 insertions(+), 12 deletions(-)

diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index a9647e90bb8..b9d32b6c0c4 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -1177,6 +1177,30 @@ void
 windows_nat_target::interrupt ()
 {
   DEBUG_EVENTS ("interrupt");
+
+  if (target_is_non_stop_p ())
+    {
+      /* Since we have finer-grained control and can suspend threads,
+	 we can report a "stopped" event for an existing thread,
+	 instead of force-injecting a new thread that reports SIGTRAP
+	 with DebugBreakProcess.
+
+	 Stop one thread, any thread.  */
+      stop_interrupt (minus_one_ptid, true);
+      return;
+    }
+
+  if (!dbg_break_process ())
+    warning (_("Could not interrupt program.  "
+	       "Press Ctrl-c in the program console."));
+}
+
+/* Stop the process with DebugBreakProcess or equivalent.  Return true
+   on success, false otherwise.  */
+
+bool
+windows_nat_target::dbg_break_process ()
+{
 #ifdef __x86_64__
   if (windows_process->wow64_process)
     {
@@ -1200,23 +1224,25 @@ windows_nat_target::interrupt ()
 	  if (thread)
 	    {
 	      CloseHandle (thread);
-	      return;
+	      return true;
 	    }
 	}
     }
   else
 #endif
     if (DebugBreakProcess (windows_process->handle))
-      return;
-  warning (_("Could not interrupt program.  "
-	     "Press Ctrl-c in the program console."));
+      return true;
+
+  return false;
 }
 
 /* Stop thread TH, for STOPPING_KIND reason.  This leaves a
    GDB_SIGNAL_0 pending in the thread, which is later consumed by
-   windows_nat_target::wait.  */
+   windows_nat_target::wait.  Return true if TH gets suspended and now
+   has a new stop event to report; false if TH was already suspended
+   and has no new stop event.  */
 
-void
+bool
 windows_nat_target::stop_one_thread (windows_thread_info *th,
 				     enum stopping_kind stopping_kind)
 {
@@ -1230,6 +1256,7 @@ windows_nat_target::stop_one_thread (windows_thread_info *th,
       DEBUG_EVENTS ("already suspended %s: suspended=%d, stopping=%d",
 		    thr_ptid.to_string ().c_str (),
 		    th->suspended, th->stopping);
+      return false;
     }
 #ifdef __CYGWIN__
   else if (th->suspended
@@ -1249,6 +1276,7 @@ windows_nat_target::stop_one_thread (windows_thread_info *th,
       th->pending_status.set_stopped (GDB_SIGNAL_0);
       th->last_event = {};
       serial_event_set (m_wait_event);
+      return true;
     }
 #endif
   else if (th->suspended)
@@ -1262,6 +1290,7 @@ windows_nat_target::stop_one_thread (windows_thread_info *th,
       /* Upgrade stopping.  */
       if (stopping_kind > th->stopping)
 	th->stopping = stopping_kind;
+      return false;
     }
   else
     {
@@ -1278,7 +1307,7 @@ windows_nat_target::stop_one_thread (windows_thread_info *th,
 			thr_ptid.to_string ().c_str ());
 	  if (stopping_kind > th->stopping)
 	    th->stopping = stopping_kind;
-	  return;
+	  return false;
 	}
 
       gdb_assert (th->suspended == 1);
@@ -1291,21 +1320,38 @@ windows_nat_target::stop_one_thread (windows_thread_info *th,
 	}
 
       serial_event_set (m_wait_event);
+      return true;
     }
 }
 
-/* Implementation of target_ops::stop.  */
+/* Helper for windows_nat_target::stop and
+   windows_nat_target::interrupt.  Stops PTID.  If STOP_ON_FIRST_MATCH
+   is true, returns immediately as soon as one thread is stopped.  */
 
 void
-windows_nat_target::stop (ptid_t ptid)
+windows_nat_target::stop_interrupt (ptid_t ptid, bool stop_on_first_match)
 {
   for (thread_info &thr : all_non_exited_threads (this))
     {
-      if (thr.ptid.matches (ptid))
-	stop_one_thread (as_windows_thread_info (&thr), SK_EXTERNAL);
+      if (!thr.ptid.matches (ptid))
+	continue;
+
+      if (stop_one_thread (as_windows_thread_info (&thr), SK_EXTERNAL))
+	{
+	  if (stop_on_first_match)
+	    return;
+	}
     }
 }
 
+/* Implementation of target_ops::stop.  */
+
+void
+windows_nat_target::stop (ptid_t ptid)
+{
+  stop_interrupt (ptid, false);
+}
+
 void
 windows_nat_target::pass_ctrlc ()
 {
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index 1f7ecb07e4f..8e6e79a8160 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -312,9 +312,12 @@ private:
   void delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p);
   DWORD fake_create_process (const DEBUG_EVENT &current_event);
 
-  void stop_one_thread (windows_thread_info *th,
+  bool stop_one_thread (windows_thread_info *th,
 			enum windows_nat::stopping_kind stopping_kind);
 
+  void stop_interrupt (ptid_t ptid, bool stop_on_first_match);
+  bool dbg_break_process ();
+
   DWORD continue_status_for_event_detaching
     (const DEBUG_EVENT &event, size_t *reply_later_events_left = nullptr);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.