Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -1062,6 +1062,8 @@ if (action == nullptr) { LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), thread->GetID()); + // Make sure we reset the stop reason for all the threads. + static_cast(*thread).ResetStopReason(); continue; } Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.h =================================================================== --- lldb/source/Plugins/Process/Linux/NativeThreadLinux.h +++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.h @@ -94,6 +94,8 @@ void SetStopped(); + void ResetStopReason(); + // Member Variables lldb::StateType m_state; ThreadStopInfo m_stop_info; Index: lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp =================================================================== --- lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -396,7 +396,10 @@ void NativeThreadLinux::SetStoppedWithNoReason() { SetStopped(); + ResetStopReason(); +} +void NativeThreadLinux::ResetStopReason() { m_stop_info.reason = StopReason::eStopReasonNone; m_stop_info.details.signal.signo = 0; } Index: lldb/test/API/functionalities/thread/break_step_other/Makefile =================================================================== --- /dev/null +++ lldb/test/API/functionalities/thread/break_step_other/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp +ENABLE_THREADS := YES + +include Makefile.rules Index: lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/thread/break_step_other/TestThreadBreakStepOther.py @@ -0,0 +1,63 @@ +""" +Test stop reasons after hitting and deleting a breakpoint and +stepping another thread. Scenario: + - run a thread + - stop the thread at a breakpoint + - delete the breakpoint + - single step on the main thread +The thread stopped at the deleted breakpoint should have stop reason +'none'. +""" + + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ThreadBreakStepOtherTestCase(TestBase): + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def test_hit_breakpoint_delete_step_other_thread(self): + main_source_file = lldb.SBFileSpec("main.cpp") + self.build() + (target, process, main_thread, _) = lldbutil.run_to_source_breakpoint( + self, "// main break here", main_source_file, only_one_thread = False) + + # Run until the breakpoint in the thread. + thread_breakpoint = target.BreakpointCreateBySourceRegex( + "// thread break here", main_source_file) + self.assertGreater( + thread_breakpoint.GetNumLocations(), + 0, + "thread breakpoint has no locations associated with it.") + process.Continue() + stopped_threads = lldbutil.get_threads_stopped_at_breakpoint( + process, thread_breakpoint) + self.assertEquals( + 1, + len(stopped_threads), + "only one thread expected stopped at the thread breakpoint") + breakpoint_thread = stopped_threads[0] + + # Delete the breakpint in the thread and do a step in the main thread. + target.BreakpointDelete(thread_breakpoint.GetID()) + main_thread.StepInstruction(False) + + # Check the stop reasons. + reason = main_thread.GetStopReason() + self.assertEqual( + lldb.eStopReasonPlanComplete, + reason, + "Expected thread stop reason 'plancomplete', but got '%s'" % + lldbutil.stop_reason_to_str(reason)) + + reason = breakpoint_thread.GetStopReason() + self.assertEqual( + lldb.eStopReasonNone, + reason, + "Expected thread stop reason 'none', but got '%s'" % + lldbutil.stop_reason_to_str(reason)) Index: lldb/test/API/functionalities/thread/break_step_other/main.cpp =================================================================== --- /dev/null +++ lldb/test/API/functionalities/thread/break_step_other/main.cpp @@ -0,0 +1,29 @@ +#include +#include "pseudo_barrier.h" + +// Barrier for starting the thread and reaching the loop in main. +pseudo_barrier_t g_barrier; +volatile int g_foo = 0; + +void thread_func() { + // Wait until all the threads are running + pseudo_barrier_wait(g_barrier); + g_foo = 1; // thread break here +} + +int main() { + g_foo = 0; // main break here + + pseudo_barrier_init(g_barrier, 2); + std::thread t(thread_func); + pseudo_barrier_wait(g_barrier); + + // A dummy loop to have something to step through. + unsigned int i = 0; + while (g_foo == 0) { + ++i; + } + + t.join(); + return 0; +}