Author: Charles Zablit
Date: 2026-06-22T17:21:38+01:00
New Revision: bd89ac741dff1a6edec15821b719a34ab5646f3f

URL: 
https://github.com/llvm/llvm-project/commit/bd89ac741dff1a6edec15821b719a34ab5646f3f
DIFF: 
https://github.com/llvm/llvm-project/commit/bd89ac741dff1a6edec15821b719a34ab5646f3f.diff

LOG: [lldb][Windows] Remember server's primary stop thread on gdb-remote stops 
(#203525)

The client kept the previously-selected thread across stops, ignoring
the primary tid from the server in `T<sig>thread:<tid>`.
On Windows, lldb-server halts the inferior by injecting a thread called
`DbgUiRemoteBreakin` whose only job is to execute an int 3. After an
interrupt, the process has `N+1` threads and the new one is what caused
the stop. The server reports that thread as primary, but the client
ignored it and stayed on whichever thread was selected before. In
`TestExpressionInSyscall` that thread is main, paused just past
`NtDelayExecution`'s syscall with a garbage value in the RSI register.
Evaluating an expression there crashes the JIT trampoline.

This patch makes `ProcessGDBRemote::RefreshStateAfterStop` record the
primary tid from the most recent T-packet's `thread:<tid>` and select it
after applying per thread stop infos.

Fixes `TestBreakpointSetRestart` and `TestExpressionInSyscall` with
LLDB_USE_LLDB_SERVER=1.

rdar://180307914

Added: 
    

Modified: 
    lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp 
b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index a986d0350bf57..85b9516a416fb 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -2636,6 +2636,8 @@ StateType 
ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
 
     SetAddressableBitMasks(addressable_bits);
 
+    m_last_stop_primary_tid = tid;
+
     ThreadSP thread_sp = SetThreadStopInfo(
         tid, expedited_register_map, signo, thread_name, reason, description,
         exc_type, exc_data, thread_dispatch_qaddr, queue_vars_valid,
@@ -2684,7 +2686,14 @@ void ProcessGDBRemote::RefreshStateAfterStop() {
   if (m_initial_tid != LLDB_INVALID_THREAD_ID) {
     m_thread_list.SetSelectedThreadByID(m_initial_tid);
     m_initial_tid = LLDB_INVALID_THREAD_ID;
-  }
+  } else if (m_last_stop_primary_tid != LLDB_INVALID_THREAD_ID &&
+             StateIsRunningState(m_last_broadcast_state)) {
+    if (ThreadSP primary_thread_sp =
+            m_thread_list.FindThreadByProtocolID(m_last_stop_primary_tid,
+                                                 /*can_update=*/false))
+      m_thread_list.SetSelectedThreadByID(primary_thread_sp->GetID());
+  }
+  m_last_stop_primary_tid = LLDB_INVALID_THREAD_ID;
 
   // Let all threads recover from stopping and do any clean up based on the
   // previous thread state (if any).

diff  --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h 
b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 0a3386082c388..7a030cd966a18 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -322,6 +322,9 @@ class ProcessGDBRemote : public Process,
   lldb::CommandObjectSP m_command_sp;
   int64_t m_breakpoint_pc_offset;
   lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach
+  lldb::tid_t m_last_stop_primary_tid =
+      LLDB_INVALID_THREAD_ID; // Thread ID extracted from the most recent
+                              // T-packet's "thread:<tid>" key.
   bool m_use_g_packet_for_reading;
 
   bool m_allow_flash_writes;


        
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to