[Lldb-commits] [lldb] [lldb][Windows] Remember server's primary stop thread on gdb-remote stops (PR #203525)
Charles Zablit via lldb-commits
lldb-commits at lists.llvm.org
Fri Jun 12 06:26:59 PDT 2026
https://github.com/charles-zablit created https://github.com/llvm/llvm-project/pull/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.
>From ea720471e242838d0c8150596eaab3bf45a6c07b Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Fri, 12 Jun 2026 14:06:40 +0100
Subject: [PATCH] [lldb][Windows] Honor server's primary stop thread on
gdb-remote stops
---
.../Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 8 ++++++++
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h | 3 +++
2 files changed, 11 insertions(+)
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 2fc6dbb546f79..754666665ae07 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -2621,6 +2621,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,
@@ -2669,7 +2671,13 @@ 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) {
+ 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;
More information about the lldb-commits
mailing list