[Lldb-commits] [lldb] [lldb][Windows] Report all queued exceptions in one lldb-server stop (PR #227353)
via lldb-commits
lldb-commits at lists.llvm.org
Tue Sep 29 08:49:04 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Charles Zablit (charles-zablit)
<details>
<summary>Changes</summary>
# Brief
Windows only gives one debug event per process at a time. When 2 threads hit the same breakpoint, the second thread's event is only received once the first thread is continued.
In this scenario, lldb-server reports the first stop from the exception handler and returns [`MaskException`](https://github.com/llvm/llvm-project/blob/34ba34d7f9bd2c756db7df96d3a5be39f006aa19/lldb/source/Plugins/Process/Windows/Common/ForwardDecl.h#L20). `DebuggerThread` continues the event immediatly and goes back to handling new events, **while the user is still looking at the stop**.
# Detailed explanation
Threads `A` and `B` both hit a breakpoint at address `X` almost at the same time.
1. The kernel sends `A`'s `EXCEPTION_BREAKPOINT`. `B` has already executed the trap, so its program counter (PC) is `X+1`, but its event has not been sent by the kernel yet.
2. lldb-server reports the stop. For `A`, `HandleBreakpointException`:
- suspends every thread (`StopThread`),
- moves `A`'s `PC` back to `X` and gives `A` a breakpoint reason,
- calls `SetState(eStateStopped, true)`, which makes LLGS build and send the stop reply immediatly.
In that reply `A` has reason breakpoint. `B` is listed with no reason and its `PC` is `X+1`.
3. The loop picks up `B`'s event. It returns `MaskException`, the event is continued, and the loop receives `B`'s queued event about 50 µs after the reply went out.
4. `B`'s breakpoint hit is applied silently. `HandleBreakpointException` runs for `B`: it gives `B` a breakpoint reason and moves `B`'s `PC` back to `X`. Its `SetState(eStateStopped, true)` does nothing, because the state is already stopped. No second stop reply is sent.
5. The client ends up with an inconsistent picture of `B`.
- From the reply, it decided `B` has no stop reason. `X+1` is not a breakpoint site, so it didn't mark `B` as `"stopped at an unexecuted breakpoint"`.
- A later `jThreadsInfo` updates `B`'s `PC` to `X`, but the client considers `B`'s stop info already current and doesn't re-read the reason.
- So `B` is at a breakpoint site with no reason and no `"unexecuted"` mark.
6. On resume the hit is lost. `Thread::SetupToStepOverBreakpointIfNeeded` sees a thread sitting on a site it supposedly already hit, and steps it over the trap.
This is how tests hang. In TestThreadStepOut, for example:
- the test waits for `B`'s breakpoint while `A` stays suspended,
- `B` runs to the end instead,
- main blocks joining `A`, so `Continue()` never returns.
# Fix
This patch collects the stop before reporting it: the exception handlers record the stop through `DeferStop`. In the meantime, `DebuggerThread` processes the events that are already queued and then reports one stop that contains every thread that hit a breakpoint. It then waits for the client to resume.
# Testing
At desk, I was able to reproduce consistent failures on a loaded machine. With the patch, the three hanging tests now pass under the same conditions.
---
Patch is 23.90 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/227353.diff
15 Files Affected:
- (modified) lldb/include/lldb/Host/common/NativeProcessProtocol.h (+4-1)
- (modified) lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp (+34-3)
- (modified) lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h (+4)
- (modified) lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h (+3)
- (modified) lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp (+77-9)
- (modified) lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h (+24)
- (modified) lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp (+1)
- (modified) lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.h (+4)
- (modified) lldb/test/API/commands/thread/backtrace/TestThreadBacktraceRepeat.py (-2)
- (modified) lldb/test/API/commands/watchpoints/hello_watchlocation/TestWatchLocation.py (-1)
- (modified) lldb/test/API/functionalities/thread/num_threads/TestNumThreads.py (+3-3)
- (modified) lldb/test/API/functionalities/thread/step_out/TestThreadStepOut.py (+7-6)
- (modified) lldb/test/API/python_api/watchpoint/watchlocation/TestSetWatchlocation.py (-1)
- (modified) lldb/test/API/tools/lldb-dap/stopped-events/TestDAP_stopped_events.py (+7-1)
- (modified) lldb/test/API/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py (-1)
``````````diff
diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index 209cb068aba21..da1fa26abefa9 100644
--- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -544,8 +544,11 @@ class NativeProcessProtocol {
NativeThreadProtocol *GetThreadByIDUnlocked(lldb::tid_t tid);
-private:
+ /// Notify the delegates of \p state. For plugins that set a state with
+ /// SetState(state, /*notify_delegates=*/false) and report it later.
void SynchronouslyNotifyProcessStateChanged(lldb::StateType state);
+
+private:
llvm::Expected<SoftwareBreakpoint>
EnableSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint);
};
diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp
index 260ac0fe0faf6..03e50675b2bd8 100644
--- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp
@@ -259,6 +259,13 @@ void DebuggerThread::ContinueAsyncException(ExceptionResult result) {
m_exception_pred.SetValue(result, eBroadcastAlways);
}
+void DebuggerThread::ReportDeferredStopAndWaitForResume() {
+ m_dll_event_pred.SetValue(false, eBroadcastNever);
+ m_debug_delegate->ReportDeferredStop();
+ if (!m_is_shutting_down)
+ m_dll_event_pred.WaitForValueEqualTo(true);
+}
+
void DebuggerThread::ContinueAsyncDllEvent() {
m_dll_event_pred.SetValue(true, eBroadcastAlways);
}
@@ -276,10 +283,28 @@ void DebuggerThread::DebugLoop() {
Log *log = GetLog(WindowsLog::Event);
DEBUG_EVENT dbe = {};
bool should_debug = true;
+ constexpr unsigned max_drained_events = 64;
+ unsigned drained_events = 0;
LLDB_LOG_VERBOSE(log, "Entering WaitForDebugEventEx loop");
while (should_debug) {
+ bool draining = !m_is_shutting_down && m_debug_delegate->HasDeferredStop();
+ if (draining && drained_events >= max_drained_events) {
+ LLDB_LOG(log, "reporting the stop after taking {0} queued debug events",
+ drained_events);
+ ReportDeferredStopAndWaitForResume();
+ draining = false;
+ }
+ if (!draining)
+ drained_events = 0;
LLDB_LOG_VERBOSE(log, "Calling WaitForDebugEvent");
- BOOL wait_result = g_wait_for_debug_event(&dbe, INFINITE);
+ BOOL wait_result = g_wait_for_debug_event(&dbe, draining ? 0 : INFINITE);
+ if (draining) {
+ if (!wait_result) {
+ ReportDeferredStopAndWaitForResume();
+ continue;
+ }
+ ++drained_events;
+ }
if (wait_result) {
DWORD continue_status = DBG_CONTINUE;
bool shutting_down = m_is_shutting_down;
@@ -432,6 +457,8 @@ DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info,
// result is what the wait below returns.
if (result != ExceptionResult::BreakInDebugger)
ContinueAsyncException(result);
+ else
+ m_debug_delegate->ReportDeferredStop();
LLDB_LOG(log, "waiting for ExceptionPred != BreakInDebugger");
result = *m_exception_pred.WaitForValueNotEqualTo(
@@ -785,8 +812,10 @@ DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info,
if (info.hFile != nullptr)
::CloseHandle(info.hFile);
- if (action == DllEventAction::ParkDebugLoop && !m_is_shutting_down.load())
+ if (action == DllEventAction::ParkDebugLoop && !m_is_shutting_down.load()) {
+ m_debug_delegate->ReportDeferredStop();
m_dll_event_pred.WaitForValueEqualTo(true);
+ }
return DBG_CONTINUE;
}
@@ -800,8 +829,10 @@ DebuggerThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info,
m_dll_event_pred.SetValue(false, eBroadcastNever);
DllEventAction action = m_debug_delegate->OnUnloadDll(
reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll), thread_id);
- if (action == DllEventAction::ParkDebugLoop && !m_is_shutting_down.load())
+ if (action == DllEventAction::ParkDebugLoop && !m_is_shutting_down.load()) {
+ m_debug_delegate->ReportDeferredStop();
m_dll_event_pred.WaitForValueEqualTo(true);
+ }
return DBG_CONTINUE;
}
diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h
index 03202264b01ee..4e81099e7afb7 100644
--- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h
+++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h
@@ -50,6 +50,10 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> {
void ContinueAsyncDllEvent();
private:
+ /// Have the delegate report the stop it collected, then wait until the
+ /// client resumes before taking the next debug event.
+ void ReportDeferredStopAndWaitForResume();
+
void FreeProcessHandles();
void DebugLoop();
ExceptionResult HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info,
diff --git a/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h
index cecd58a15f9c2..f5c9b53447f3b 100644
--- a/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h
+++ b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h
@@ -37,6 +37,9 @@ class IDebugDelegate {
lldb::tid_t thread_id) = 0;
virtual DllEventAction OnUnloadDll(lldb::addr_t module_addr,
lldb::tid_t thread_id) = 0;
+ virtual bool HasDeferredStop() { return false; }
+ /// Report the stop the delegate holds, if any.
+ virtual void ReportDeferredStop() {}
virtual void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode,
uint16_t length_lower_word) = 0;
virtual void OnDebuggerError(const Status &error, uint32_t type) = 0;
diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index 849931eaec372..7e311cf28ea7d 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -519,6 +519,9 @@ void NativeProcessWindows::OnExitProcess(uint32_t exit_code) {
ProcessDebugger::OnExitProcess(exit_code);
+ // The exit replaces a stop that has not been reported yet.
+ m_deferred_stop = false;
+
// No signal involved. It is just an exit event.
WaitStatus wait_status(WaitStatus::Exit, exit_code);
SetExitStatus(wait_status, true);
@@ -563,6 +566,57 @@ void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
*this, m_session_data->m_debugger->GetMainThread()));
}
+void NativeProcessWindows::DeferStop() {
+ if (GetState() == eStateStopped) {
+ if (!m_deferred_stop)
+ LLDB_LOG(GetLog(WindowsLog::Exception),
+ "debug event on thread {0:x} while a reported stop is current",
+ GetCurrentThreadID());
+ return;
+ }
+ SetState(eStateStopped, /*notify_delegates=*/false);
+ m_deferred_stop = true;
+ m_deferred_stop_tid = GetCurrentThreadID();
+}
+
+void NativeProcessWindows::ReportDeferredStop() {
+ llvm::sys::ScopedLock lock(m_mutex);
+ if (!m_deferred_stop)
+ return;
+ m_deferred_stop = false;
+ if (GetThreadByID(m_deferred_stop_tid))
+ SetCurrentThreadID(m_deferred_stop_tid);
+ SynchronouslyNotifyProcessStateChanged(eStateStopped);
+}
+
+bool NativeProcessWindows::RewindTrapOfRemovedBreakpoint(
+ const ExceptionRecord &record) {
+ if (!m_initial_stop_seen)
+ return false;
+ NativeThreadWindows *thread = GetThreadByID(record.GetThreadID());
+ if (!thread)
+ return false;
+ const lldb::addr_t trap_addr = record.GetExceptionAddress();
+ llvm::ArrayRef<uint8_t> trap_opcode =
+ cantFail(GetSoftwareBreakpointTrapOpcode(0));
+ NativeRegisterContextWindows ®_ctx = thread->GetRegisterContext();
+ if (reg_ctx.GetPC() != trap_addr + trap_opcode.size())
+ return false;
+ llvm::SmallVector<uint8_t, 4> bytes(trap_opcode.size(), 0);
+ size_t bytes_read = 0;
+ if (ProcessDebugger::ReadMemory(trap_addr, bytes.data(), bytes.size(),
+ bytes_read)
+ .Fail() ||
+ bytes_read != bytes.size() ||
+ llvm::ArrayRef<uint8_t>(bytes) == trap_opcode)
+ return false;
+ LLDB_LOG(GetLog(WindowsLog::Exception),
+ "Trap at {0:x} on thread {1:x} is from a removed breakpoint, "
+ "rewinding the thread onto the original instruction.",
+ trap_addr, thread->GetID());
+ return reg_ctx.SetPC(trap_addr).Success();
+}
+
ExceptionResult
NativeProcessWindows::HandleSingleStepException(const ExceptionRecord &record) {
uint32_t wp_id = LLDB_INVALID_INDEX32;
@@ -586,10 +640,19 @@ NativeProcessWindows::HandleSingleStepException(const ExceptionRecord &record) {
}
}
#endif
- if (wp_id == LLDB_INVALID_INDEX32)
+ if (wp_id == LLDB_INVALID_INDEX32) {
+ NativeThreadWindows *thread = GetThreadByID(record.GetThreadID());
+ if (thread && !thread->IsSingleStepping()) {
+ LLDB_LOG(GetLog(WindowsLog::Exception),
+ "ignoring a late single-step trap on thread {0:x}, which this "
+ "resume did not step",
+ record.GetThreadID());
+ return ExceptionResult::MaskException;
+ }
StopThread(record.GetThreadID(), StopReason::eStopReasonTrace);
+ }
- SetState(eStateStopped, true);
+ DeferStop();
return ExceptionResult::MaskException;
}
@@ -608,7 +671,7 @@ NativeProcessWindows::HandleBreakpointException(const ExceptionRecord &record) {
StopThread(thread_id, StopReason::eStopReasonBreakpoint);
// The current PC is AFTER the BP opcode, on all architectures.
reg_ctx.SetPC(reg_ctx.GetPC() - GetSoftwareBreakpointPCOffset());
- SetState(eStateStopped, true);
+ DeferStop();
return ExceptionResult::MaskException;
}
@@ -635,10 +698,13 @@ NativeProcessWindows::HandleBreakpointException(const ExceptionRecord &record) {
exception_addr)
.str();
StopThread(thread_id, StopReason::eStopReasonWatchpoint, desc);
- SetState(eStateStopped, true);
+ DeferStop();
return ExceptionResult::MaskException;
}
}
+
+ if (RewindTrapOfRemovedBreakpoint(record))
+ return ExceptionResult::MaskException;
}
if (!m_initial_stop_seen) {
@@ -686,7 +752,7 @@ NativeProcessWindows::HandleBreakpointException(const ExceptionRecord &record) {
SetCurrentThreadID(thread_id);
if (NativeThreadWindows *injected = GetThreadByID(thread_id))
injected->SetStopReason(signal_info, "interrupt");
- SetState(eStateStopped, true);
+ DeferStop();
return ExceptionResult::BreakInDebugger;
}
@@ -703,7 +769,7 @@ NativeProcessWindows::HandleBreakpointException(const ExceptionRecord &record) {
record.GetExceptionValue(), exception_addr)
.str();
StopThread(thread_id, StopReason::eStopReasonException, std::move(desc));
- SetState(eStateStopped, true);
+ DeferStop();
return ExceptionResult::MaskException;
}
@@ -729,7 +795,7 @@ NativeProcessWindows::HandleGenericException(bool first_chance,
StopThread(record.GetThreadID(), StopReason::eStopReasonException,
std::move(desc));
- SetState(eStateStopped, true);
+ DeferStop();
return ExceptionResult::BreakInDebugger;
}
@@ -762,6 +828,8 @@ NativeProcessWindows::OnDebugException(bool first_chance,
void NativeProcessWindows::OnCreateThread(const HostThread &new_thread) {
llvm::sys::ScopedLock lock(m_mutex);
+ const StateType state = GetState();
+ std::lock_guard<std::recursive_mutex> threads_guard(m_threads_mutex);
auto thread = std::make_unique<NativeThreadWindows>(*this, new_thread);
thread->GetRegisterContext().ClearAllHardwareWatchpoints();
@@ -771,8 +839,7 @@ void NativeProcessWindows::OnCreateThread(const HostThread &new_thread) {
wp.m_hardware);
}
- if (StateType state = GetState();
- state == eStateStopped || state == eStateCrashed) {
+ if (state == eStateStopped || state == eStateCrashed) {
if (Status error = thread->DoStop(); error.Fail()) {
Log *log = GetLog(WindowsLog::Thread);
LLDB_LOG(log, "failed to suspend newly-created thread {0}: {1}",
@@ -788,6 +855,7 @@ void NativeProcessWindows::OnCreateThread(const HostThread &new_thread) {
void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id,
uint32_t exit_code) {
+ llvm::sys::ScopedLock lock(m_mutex);
std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
llvm::erase_if(m_threads, [thread_id](const auto &t) {
return t->GetID() == thread_id;
diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
index 114b4a200e18c..79046dd6846a4 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
@@ -140,6 +140,8 @@ class NativeProcessWindows : public NativeProcessProtocol,
lldb::tid_t thread_id) override;
void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode,
uint16_t length_lower_word) override;
+ bool HasDeferredStop() const { return m_deferred_stop; }
+ void ReportDeferredStop();
protected:
NativeThreadWindows *GetThreadByID(lldb::tid_t thread_id);
@@ -167,6 +169,16 @@ class NativeProcessWindows : public NativeProcessProtocol,
NativeProcessWindows(lldb::pid_t pid, int terminal_fd,
NativeDelegate &delegate, llvm::Error &E);
+ /// Stop the process without notifying the delegate yet.
+ void DeferStop();
+
+ /// A breakpoint trap whose debug event was only delivered after the client
+ /// removed that breakpoint: the thread executed the trap before the stop
+ /// that removed it, but its event was held back until it ran again. Moves
+ /// the PC back onto the original instruction. Returns false if \p record is
+ /// not such a trap.
+ bool RewindTrapOfRemovedBreakpoint(const ExceptionRecord &record);
+
ExceptionResult HandleSingleStepException(const ExceptionRecord &record);
ExceptionResult HandleBreakpointException(const ExceptionRecord &record);
ExceptionResult HandleGenericException(bool first_chance,
@@ -189,6 +201,14 @@ class NativeProcessWindows : public NativeProcessProtocol,
/// Set when Halt() / Interrupt() schedules a DebugBreakProcess injection.
bool m_pending_halt = false;
+ /// Set by DeferStop(), cleared once the stop is reported or the process
+ /// exits.
+ bool m_deferred_stop = false;
+
+ /// The thread whose debug event started the deferred stop. Reported as the
+ /// stop's thread even if later events made another thread current.
+ lldb::tid_t m_deferred_stop_tid = LLDB_INVALID_THREAD_ID;
+
bool m_client_supports_libraries_read = false;
/// PseudoConsole for the lldb-server stdio-forwarding path.
@@ -257,6 +277,10 @@ class NativeDebugDelegate : public IDebugDelegate {
return m_process.OnDebuggerError(error, type);
}
+ bool HasDeferredStop() override { return m_process.HasDeferredStop(); }
+
+ void ReportDeferredStop() override { m_process.ReportDeferredStop(); }
+
private:
NativeProcessWindows &m_process;
};
diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp
index 0842968f25d60..0c6761e1027c0 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp
@@ -95,6 +95,7 @@ Status NativeThreadWindows::DoResume(lldb::StateType resume_state) {
} while (previous_suspend_count > 1);
m_state = eStateRunning;
+ m_single_stepping = resume_state == eStateStepping;
}
return Status();
diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.h
index 392a5b9a2a7d4..fca4095ac8888 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.h
@@ -28,6 +28,9 @@ class NativeThreadWindows : public NativeThreadProtocol {
Status DoStop();
Status DoResume(lldb::StateType resume_state);
+ /// Whether the last DoResume() single-stepped this thread.
+ bool IsSingleStepping() const { return m_single_stepping; }
+
std::string GetName() override;
lldb::StateType GetState() override { return m_state; }
@@ -55,6 +58,7 @@ class NativeThreadWindows : public NativeThreadProtocol {
protected:
lldb::StateType m_state = lldb::StateType::eStateInvalid;
std::string m_name;
+ bool m_single_stepping = false;
std::unique_ptr<NativeRegisterContextWindows> m_reg_context_up;
// Cache address and index of the watchpoints and hardware breakpoints since
// the register context does not.
diff --git a/lldb/test/API/commands/thread/backtrace/TestThreadBacktraceRepeat.py b/lldb/test/API/commands/thread/backtrace/TestThreadBacktraceRepeat.py
index 50ed9dfe1b31c..7eb1f116a772b 100644
--- a/lldb/test/API/commands/thread/backtrace/TestThreadBacktraceRepeat.py
+++ b/lldb/test/API/commands/thread/backtrace/TestThreadBacktraceRepeat.py
@@ -128,8 +128,6 @@ def check_two_threads(
# the comments whether it was getting two threads to the same breakpoint that was
# problematic, or the step-out part. This test stops at the rendevous point so I'm
# removing the skipIfLinux to see if we see any flakiness in just this part of the test.
- @skipIfWindows # This test will hang on windows llvm.org/pr21753
- @expectedFailureAll(oslist=["windows"])
@expectedFailureNetBSD
def test_thread_backtrace_two_threads(self):
"""Test that repeat works even when backtracing on more than one thread."""
diff --git a/lldb/test/API/commands/watchpoints/hello_watchlocation/TestWatchLocation.py b/lldb/test/API/commands/watchpoints/hello_watchlocation/TestWatchLocation.py
index bce56ce6e79e4..8986fd6fa88d2 100644
--- a/lldb/test/API/commands/watchpoints/hello_watchlocation/TestWatchLocation.py
+++ b/lldb/test/API/commands/watchpoints/hello_watchlocation/TestWatchLocation.py
@@ -43,7 +43,6 @@ def affected_by_radar_93863107(self):
@expectedFailureAll(triple=re.compile("^mips"))
# SystemZ and PowerPC also currently supports only one H/W watchpoint
@expectedFailureAll(archs=["powerpc64le", "s390x"])
- @skipIfWindows # This test is flaky on Windows
def test_hello_watchlocation(self):
"""Test watching a location with '-s size' option."""
self.build(dictionary=self.d)
diff --git a/lldb/test/API/functionalities/thread/num_threads/TestNumThreads.py b/lldb/test/API/functionalities/thread/num_threads/TestNumThreads.py
index e6a8647f6b9cf..2787c751693e4 100644
--- a/lldb/test/API/functionalities/thread/num_threads/TestNumThreads.py
+++ b/lldb/test/API/functionalities/thread/num_threads/TestNumThreads.py
@@ -71,7 +71,6 @@ def test_number_of_threads(self):
)
@skipIfDarwin # rdar://33462362
- @skipIfWindows # This is flakey on Windows: llvm.org/pr37658, llvm.org/pr38373
def test_unique_stacks(self):
"""Test backtrace unique with multiple threads executing the same stack."""
self.build()
@@ -124,11 +123,12 @@ def is_thread3(thread):
continue
# If we aren't stopped out the thread breakpoint try to resume.
+ index_id = thread.GetIndexID()
if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
- self.runCmd("thread continue %d" % (i + 1))
+ self.runCmd("thread continue %d" % index_id)
self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonBreakpoint)
- expect_threads += " #%d" % (i + 1)
+ expect_threads += " #%d" % index_id
# Construct our expected back trace string
expect_string = "10 thread(s)%s" % (expect_threads)
diff --git a/lldb/test/API/functionalities/thread/step_out/TestThreadStepOut.py b/lldb/test/API/functionalities/thread/step_out/TestThreadStepOut.py
index a7e7b43a398c5..3f6f62ba742d5 100644
--- a/lldb/test/API/functionalities/thread/step_out/TestThrea...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/227353
More information about the lldb-commits
mailing list