Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/hello_watchlocation/TestWatchLocation.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/hello_watchlocation/TestWatchLocation.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/hello_watchlocation/TestWatchLocation.py @@ -31,9 +31,6 @@ self.exe_name = self.testMethodName self.d = {'CXX_SOURCES': self.source, 'EXE': self.exe_name} - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Most of the MIPS boards provide only one H/W watchpoints, and S/W # watchpoints are not supported yet @expectedFailureAll(triple=re.compile('^mips')) Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/hello_watchpoint/TestMyFirstWatchpoint.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/hello_watchpoint/TestMyFirstWatchpoint.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/hello_watchpoint/TestMyFirstWatchpoint.py @@ -29,9 +29,6 @@ self.exe_name = self.getBuildArtifact('a.out') self.d = {'C_SOURCES': self.source, 'EXE': self.exe_name} - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @add_test_categories(["basic_process"]) def test_hello_watchpoint_using_watchpoint_set(self): """Test a simple sequence of watchpoint creation and watchpoint hit.""" Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/multiple_hits/TestMultipleHits.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/multiple_hits/TestMultipleHits.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/multiple_hits/TestMultipleHits.py @@ -16,9 +16,6 @@ mydir = TestBase.compute_mydir(__file__) NO_DEBUG_INFO_TESTCASE = True - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @skipIf(bugnumber="llvm.org/pr30758", oslist=["linux"], archs=["arm", "aarch64", "powerpc64le"]) @skipIfwatchOS def test(self): Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/multiple_threads/TestWatchpointMultipleThreads.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/multiple_threads/TestWatchpointMultipleThreads.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/multiple_threads/TestWatchpointMultipleThreads.py @@ -18,17 +18,11 @@ NO_DEBUG_INFO_TESTCASE = True main_spec = lldb.SBFileSpec("main.cpp", False) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @expectedFailureNetBSD def test_watchpoint_before_thread_start(self): """Test that we can hit a watchpoint we set before starting another thread""" self.do_watchpoint_test("Before running the thread") - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @expectedFailureNetBSD def test_watchpoint_after_thread_start(self): """Test that we can hit a watchpoint we set after starting another thread""" @@ -66,9 +60,6 @@ self.expect("watchpoint list -v", substrs=['hit_count = 1']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") def test_watchpoint_multiple_threads_wp_set_and_then_delete(self): """Test that lldb watchpoint works for multiple threads, and after the watchpoint is deleted, the watchpoint event should no longer fires.""" self.build() Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/step_over_watchpoint/TestStepOverWatchpoint.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/step_over_watchpoint/TestStepOverWatchpoint.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/step_over_watchpoint/TestStepOverWatchpoint.py @@ -19,9 +19,6 @@ 'aarch64', 'arm'], bugnumber="llvm.org/pr26031") - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) @expectedFailureAll(oslist=["ios", "watchos", "tvos", "bridgeos"], bugnumber="") # watchpoint tests aren't working on arm64 Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/TestWatchpointCommands.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/TestWatchpointCommands.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/TestWatchpointCommands.py @@ -34,9 +34,6 @@ self.exe_name = self.testMethodName self.d = {'C_SOURCES': self.source, 'EXE': self.exe_name} - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_rw_watchpoint(self): @@ -105,9 +102,6 @@ self.expect("watchpoint list -v", substrs=['hit_count = 2']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_rw_watchpoint_delete(self): @@ -162,9 +156,6 @@ self.expect("process status", substrs=['exited']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_rw_watchpoint_set_ignore_count(self): @@ -222,9 +213,6 @@ self.expect("watchpoint list -v", substrs=['hit_count = 2', 'ignore_count = 2']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_rw_disable_after_first_stop(self): @@ -292,9 +280,6 @@ self.expect("watchpoint list -v", substrs=['hit_count = 1']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_rw_disable_then_enable(self): Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/command/TestWatchpointCommandLLDB.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/command/TestWatchpointCommandLLDB.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/command/TestWatchpointCommandLLDB.py @@ -36,9 +36,6 @@ archs=["aarch64"], triple=no_match(".*-android"), bugnumber="llvm.org/pr27710") # work on android - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @expectedFailureNetBSD def test_watchpoint_command(self): """Test 'watchpoint command'.""" @@ -106,9 +103,6 @@ archs=["aarch64"], triple=no_match(".*-android"), bugnumber="llvm.org/pr27710") # work on android - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") def test_watchpoint_command_can_disable_a_watchpoint(self): """Test that 'watchpoint command' action can disable a watchpoint after it is triggered.""" self.build(dictionary=self.d) Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/command/TestWatchpointCommandPython.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/command/TestWatchpointCommandPython.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/command/TestWatchpointCommandPython.py @@ -34,9 +34,6 @@ @skipIfFreeBSD # timing out on buildbot @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") - @expectedFailureAll( oslist=["linux"], archs=["aarch64"], triple=no_match(".*-android"), @@ -106,9 +103,6 @@ @skipIfFreeBSD # timing out on buildbot @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") - @expectedFailureAll( oslist=["linux"], archs=["aarch64"], triple=no_match(".*-android"), Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/condition/TestWatchpointConditionCmd.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/condition/TestWatchpointConditionCmd.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/condition/TestWatchpointConditionCmd.py @@ -36,9 +36,6 @@ archs=["aarch64"], triple=no_match(".*-android"), bugnumber="llvm.org/pr27710") - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @expectedFailureNetBSD def test_watchpoint_cond(self): """Test watchpoint condition.""" Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_disable/TestWatchpointDisable.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_disable/TestWatchpointDisable.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_disable/TestWatchpointDisable.py @@ -15,17 +15,11 @@ # Call super's setUp(). TestBase.setUp(self) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") def test_disable_works (self): """Set a watchpoint, disable it, and make sure it doesn't get hit.""" self.build() self.do_test(False) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") def test_disable_enable_works (self): """Set a watchpoint, disable it, and make sure it doesn't get hit.""" self.build() Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_events/TestWatchpointEvents.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_events/TestWatchpointEvents.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_events/TestWatchpointEvents.py @@ -25,9 +25,6 @@ archs=["aarch64"], triple=no_match(".*-android"), bugnumber="llvm.org/pr27710") - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") def test_with_python_api(self): """Test that adding, deleting and modifying watchpoints sends the appropriate events.""" self.build() Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_on_vectors/TestValueOfVectorVariable.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_on_vectors/TestValueOfVectorVariable.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_on_vectors/TestValueOfVectorVariable.py @@ -15,9 +15,6 @@ mydir = TestBase.compute_mydir(__file__) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") def test_value_of_vector_variable_using_watchpoint_set(self): """Test verify displayed value of vector variable.""" exe = self.getBuildArtifact("a.out") Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_set_command/TestWatchLocationWithWatchSet.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_set_command/TestWatchLocationWithWatchSet.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_set_command/TestWatchLocationWithWatchSet.py @@ -34,9 +34,6 @@ 'aarch64', 'arm'], bugnumber="llvm.org/pr26031") - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @expectedFailureNetBSD def test_watchlocation_using_watchpoint_set(self): """Test watching a location with 'watchpoint set expression -w write -s size' option.""" Index: lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_size/TestWatchpointSizes.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_size/TestWatchpointSizes.py +++ lldb/trunk/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_size/TestWatchpointSizes.py @@ -29,27 +29,18 @@ self.exe_name = self.getBuildArtifact("a.out") self.d = {'C_SOURCES': self.source, 'EXE': self.exe_name} - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_byte_size_watchpoints_with_byte_selection(self): """Test to selectively watch different bytes in a 8-byte array.""" self.run_watchpoint_size_test('byteArray', 8, '1') - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_two_byte_watchpoints_with_word_selection(self): """Test to selectively watch different words in an 8-byte word array.""" self.run_watchpoint_size_test('wordArray', 4, '2') - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_four_byte_watchpoints_with_dword_selection(self): Index: lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/TestSetWatchpoint.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/TestSetWatchpoint.py +++ lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/TestSetWatchpoint.py @@ -25,9 +25,6 @@ self.source, '// Set break point at this line.') @add_test_categories(['pyapi']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_watch_val(self): Index: lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIgnoreCount.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIgnoreCount.py +++ lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIgnoreCount.py @@ -25,9 +25,6 @@ self.source, '// Set break point at this line.') @add_test_categories(['pyapi']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_set_watch_ignore_count(self): Index: lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIter.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIter.py +++ lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIter.py @@ -30,9 +30,6 @@ self.source, '// Set break point at this line.') @add_test_categories(['pyapi']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") def test_watch_iter(self): """Exercise SBTarget.watchpoint_iter() API to iterate on the available watchpoints.""" self.build() Index: lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py +++ lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py @@ -36,7 +36,6 @@ archs=["aarch64"], triple=no_match(".*-android"), bugnumber="llvm.org/pr27710") - @skipIfWindows # Watchpoints not supported on Windows, and this test hangs def test_watchpoint_cond_api(self): """Test watchpoint condition API.""" self.build(dictionary=self.d) Index: lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestSetWatchlocation.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestSetWatchlocation.py +++ lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestSetWatchlocation.py @@ -28,9 +28,6 @@ self.violating_func = "do_bad_thing_with_location" @add_test_categories(['pyapi']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @expectedFailureNetBSD def test_watch_location(self): """Exercise SBValue.WatchPointee() API to set a watchpoint.""" Index: lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py +++ lldb/trunk/packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py @@ -27,9 +27,6 @@ self.violating_func = "do_bad_thing_with_location" @add_test_categories(['pyapi']) - @expectedFailureAll( - oslist=["windows"], - bugnumber="llvm.org/pr24446: WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows") @expectedFailureNetBSD def test_watch_address(self): """Exercise SBTarget.WatchAddress() API to set a watchpoint.""" Index: lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h +++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessDebugger.h @@ -41,7 +41,7 @@ HANDLE m_initial_stop_event = nullptr; bool m_initial_stop_received = false; bool m_stop_at_entry; - std::map m_new_threads; + std::map m_new_threads; std::set m_exited_threads; }; Index: lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -98,6 +98,22 @@ void OnUnloadDll(lldb::addr_t module_addr) override; void OnDebugString(const std::string &string) override; void OnDebuggerError(const Status &error, uint32_t type) override; + + Status GetWatchpointSupportInfo(uint32_t &num) override; + Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override; + Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override; + Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override; + +private: + struct WatchpointInfo { + uint32_t slot_id; + lldb::addr_t address; + uint32_t size; + bool read; + bool write; + }; + std::map m_watchpoints; + std::vector m_watchpoint_ids; }; } // namespace lldb_private Index: lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ lldb/trunk/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -12,6 +12,7 @@ #include "lldb/Host/windows/windows.h" #include +#include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -104,7 +105,10 @@ ProcessWindows::ProcessWindows(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp) - : lldb_private::Process(target_sp, listener_sp) {} + : lldb_private::Process(target_sp, listener_sp), + m_watchpoint_ids( + RegisterContextWindows::GetNumHardwareBreakpointSlots(), + LLDB_INVALID_BREAK_ID) {} ProcessWindows::~ProcessWindows() {} @@ -382,11 +386,35 @@ stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread, site->GetID()); stop_thread->SetStopInfo(stop_info); - } else { - LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID()); - stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread); + + return; + } + + auto *reg_ctx = static_cast( + stop_thread->GetRegisterContext().get()); + uint32_t slot_id = reg_ctx->GetTriggeredHardwareBreakpointSlotId(); + if (slot_id != LLDB_INVALID_INDEX32) { + int id = m_watchpoint_ids[slot_id]; + LLDB_LOG(log, + "Single-stepped onto a watchpoint in process {0} at address " + "{1:x} with watchpoint {2}", + m_session_data->m_debugger->GetProcess().GetProcessId(), pc, id); + + if (lldb::WatchpointSP wp_sp = + GetTarget().GetWatchpointList().FindByID(id)) + wp_sp->SetHardwareIndex(slot_id); + + stop_info = StopInfo::CreateStopReasonWithWatchpointID( + *stop_thread, id, m_watchpoints[id].address); stop_thread->SetStopInfo(stop_info); + + return; } + + LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID()); + stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread); + stop_thread->SetStopInfo(stop_info); + return; } @@ -494,9 +522,7 @@ // Also add all the threads that are new since the last time we broke into // the debugger. for (const auto &thread_info : m_session_data->m_new_threads) { - ThreadSP thread(new TargetThreadWindows(*this, thread_info.second)); - thread->SetID(thread_info.first); - new_thread_list.AddThread(thread); + new_thread_list.AddThread(thread_info.second); ++new_size; ++new_threads; LLDB_LOGV(log, "Thread {0} is new since last update.", thread_info.first); @@ -588,9 +614,9 @@ SetProcessExitStatus(GetID(), true, 0, exit_code); SetPrivateState(eStateExited); - // If the process exits before any initial stop then notify the debugger + // If the process exits before any initial stop then notify the debugger // of the error otherwise WaitForDebuggerConnection() will be blocked. - // An example of this issue is when a process fails to load a dependent DLL. + // An example of this issue is when a process fails to load a dependent DLL. if (m_session_data && !m_session_data->m_initial_stop_received) { Status error(exit_code, eErrorTypeWin32); OnDebuggerError(error, 0); @@ -619,8 +645,8 @@ FileSystem::Instance().Resolve(executable_file); ModuleSpec module_spec(executable_file); Status error; - module = GetTarget().GetOrCreateModule(module_spec, - true /* notify */, &error); + module = + GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error); if (!module) { return; } @@ -636,10 +662,15 @@ // returned from DoLaunch() / DoAttach() yet so the target may not have set // the process instance to `this` yet. llvm::sys::ScopedLock lock(m_mutex); - const HostThreadWindows &wmain_thread = - debugger->GetMainThread().GetNativeThread(); - m_session_data->m_new_threads[wmain_thread.GetThreadId()] = - debugger->GetMainThread(); + + const HostThread &host_main_thread = debugger->GetMainThread(); + ThreadSP main_thread = + std::make_shared(*this, host_main_thread); + + tid_t id = host_main_thread.GetNativeThread().GetThreadId(); + main_thread->SetID(id); + + m_session_data->m_new_threads[id] = main_thread; } ExceptionResult @@ -711,8 +742,22 @@ void ProcessWindows::OnCreateThread(const HostThread &new_thread) { llvm::sys::ScopedLock lock(m_mutex); - const HostThreadWindows &wnew_thread = new_thread.GetNativeThread(); - m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread; + + ThreadSP thread = std::make_shared(*this, new_thread); + + const HostNativeThread &native_new_thread = new_thread.GetNativeThread(); + tid_t id = native_new_thread.GetThreadId(); + thread->SetID(id); + + m_session_data->m_new_threads[id] = thread; + + for (const std::map::value_type &p : m_watchpoints) { + auto *reg_ctx = static_cast( + thread->GetRegisterContext().get()); + reg_ctx->AddHardwareBreakpoint(p.second.slot_id, p.second.address, + p.second.size, p.second.read, + p.second.write); + } } void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { @@ -770,4 +815,106 @@ return; } } + +Status ProcessWindows::GetWatchpointSupportInfo(uint32_t &num) { + num = RegisterContextWindows::GetNumHardwareBreakpointSlots(); + return {}; +} + +Status ProcessWindows::GetWatchpointSupportInfo(uint32_t &num, bool &after) { + num = RegisterContextWindows::GetNumHardwareBreakpointSlots(); + after = RegisterContextWindows::DoHardwareBreakpointsTriggerAfter(); + return {}; +} + +Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) { + Status error; + + if (wp->IsEnabled()) { + wp->SetEnabled(true, notify); + return error; + } + + WatchpointInfo info; + for (info.slot_id = 0; + info.slot_id < RegisterContextWindows::GetNumHardwareBreakpointSlots(); + info.slot_id++) + if (m_watchpoint_ids[info.slot_id] == LLDB_INVALID_BREAK_ID) + break; + if (info.slot_id == RegisterContextWindows::GetNumHardwareBreakpointSlots()) { + error.SetErrorStringWithFormat("Can't find free slot for watchpoint %i", + wp->GetID()); + return error; + } + info.address = wp->GetLoadAddress(); + info.size = wp->GetByteSize(); + info.read = wp->WatchpointRead(); + info.write = wp->WatchpointWrite(); + + for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) { + Thread *thread = m_thread_list.GetThreadAtIndex(i).get(); + auto *reg_ctx = static_cast( + thread->GetRegisterContext().get()); + if (!reg_ctx->AddHardwareBreakpoint(info.slot_id, info.address, info.size, + info.read, info.write)) { + error.SetErrorStringWithFormat( + "Can't enable watchpoint %i on thread 0x%llx", wp->GetID(), + thread->GetID()); + break; + } + } + if (error.Fail()) { + for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) { + Thread *thread = m_thread_list.GetThreadAtIndex(i).get(); + auto *reg_ctx = static_cast( + thread->GetRegisterContext().get()); + reg_ctx->RemoveHardwareBreakpoint(info.slot_id); + } + return error; + } + + m_watchpoints[wp->GetID()] = info; + m_watchpoint_ids[info.slot_id] = wp->GetID(); + + wp->SetEnabled(true, notify); + + return error; +} + +Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) { + Status error; + + if (!wp->IsEnabled()) { + wp->SetEnabled(false, notify); + return error; + } + + auto it = m_watchpoints.find(wp->GetID()); + if (it == m_watchpoints.end()) { + error.SetErrorStringWithFormat("Info about watchpoint %i is not found", + wp->GetID()); + return error; + } + + for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) { + Thread *thread = m_thread_list.GetThreadAtIndex(i).get(); + auto *reg_ctx = static_cast( + thread->GetRegisterContext().get()); + if (!reg_ctx->RemoveHardwareBreakpoint(it->second.slot_id)) { + error.SetErrorStringWithFormat( + "Can't disable watchpoint %i on thread 0x%llx", wp->GetID(), + thread->GetID()); + break; + } + } + if (error.Fail()) + return error; + + m_watchpoint_ids[it->second.slot_id] = LLDB_INVALID_BREAK_ID; + m_watchpoints.erase(it); + + wp->SetEnabled(false, notify); + + return error; +} } // namespace lldb_private Index: lldb/trunk/source/Plugins/Process/Windows/Common/RegisterContextWindows.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/RegisterContextWindows.h +++ lldb/trunk/source/Plugins/Process/Windows/Common/RegisterContextWindows.h @@ -33,28 +33,28 @@ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) override; - // Subclasses can override these functions if desired - uint32_t NumSupportedHardwareBreakpoints() override; - - uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; - - bool ClearHardwareBreakpoint(uint32_t hw_idx) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, - bool write) override; + bool HardwareSingleStep(bool enable) override; - bool ClearHardwareWatchpoint(uint32_t hw_index) override; + static constexpr uint32_t GetNumHardwareBreakpointSlots() { + return NUM_HARDWARE_BREAKPOINT_SLOTS; + } + static constexpr bool DoHardwareBreakpointsTriggerAfter() { return true; } + + bool AddHardwareBreakpoint(uint32_t slot, lldb::addr_t address, uint32_t size, + bool read, bool write); + bool RemoveHardwareBreakpoint(uint32_t slot); - bool HardwareSingleStep(bool enable) override; + uint32_t GetTriggeredHardwareBreakpointSlotId(); protected: + static constexpr unsigned NUM_HARDWARE_BREAKPOINT_SLOTS = 4; + virtual bool CacheAllRegisterValues(); + virtual bool ApplyAllRegisterValues(); CONTEXT m_context; bool m_context_stale; }; -} +} // namespace lldb_private #endif // #ifndef liblldb_RegisterContextWindows_H_ Index: lldb/trunk/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp +++ lldb/trunk/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp @@ -17,6 +17,7 @@ #include "TargetThreadWindows.h" #include "llvm/ADT/STLExtras.h" +#include "lldb/Target/Target.h" using namespace lldb; using namespace lldb_private; @@ -52,13 +53,7 @@ assert(data_sp->GetByteSize() >= sizeof(m_context)); memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context)); - TargetThreadWindows &wthread = static_cast(m_thread); - if (!::SetThreadContext( - wthread.GetHostThread().GetNativeThread().GetSystemHandle(), - &m_context)) - return false; - - return true; + return ApplyAllRegisterValues(); } uint32_t RegisterContextWindows::ConvertRegisterKindToRegisterNumber( @@ -76,37 +71,69 @@ return LLDB_INVALID_REGNUM; } -// Subclasses can these functions if desired -uint32_t RegisterContextWindows::NumSupportedHardwareBreakpoints() { - // Support for hardware breakpoints not yet implemented. - return 0; -} +bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; } -uint32_t RegisterContextWindows::SetHardwareBreakpoint(lldb::addr_t addr, - size_t size) { - return 0; -} +bool RegisterContextWindows::AddHardwareBreakpoint(uint32_t slot, + lldb::addr_t address, + uint32_t size, bool read, + bool write) { + if (slot >= NUM_HARDWARE_BREAKPOINT_SLOTS) + return false; + + switch (size) { + case 1: + case 2: + case 4: +#if defined(_M_AMD64) + case 8: +#endif + break; + default: + return false; + } -bool RegisterContextWindows::ClearHardwareBreakpoint(uint32_t hw_idx) { - return false; -} + if (!CacheAllRegisterValues()) + return false; -uint32_t RegisterContextWindows::NumSupportedHardwareWatchpoints() { - // Support for hardware watchpoints not yet implemented. - return 0; -} + unsigned shift = 2 * slot; + m_context.Dr7 |= 1ULL << shift; + + (&m_context.Dr0)[slot] = address; + + shift = 18 + 4 * slot; + m_context.Dr7 &= ~(3ULL << shift); + m_context.Dr7 |= (size == 8 ? 2ULL : size - 1) << shift; -uint32_t RegisterContextWindows::SetHardwareWatchpoint(lldb::addr_t addr, - size_t size, bool read, - bool write) { - return 0; + shift = 16 + 4 * slot; + m_context.Dr7 &= ~(3ULL << shift); + m_context.Dr7 |= (read ? 3ULL : (write ? 1ULL : 0)) << shift; + + return ApplyAllRegisterValues(); } -bool RegisterContextWindows::ClearHardwareWatchpoint(uint32_t hw_index) { - return false; +bool RegisterContextWindows::RemoveHardwareBreakpoint(uint32_t slot) { + if (slot >= NUM_HARDWARE_BREAKPOINT_SLOTS) + return false; + + if (!CacheAllRegisterValues()) + return false; + + unsigned shift = 2 * slot; + m_context.Dr7 &= ~(1ULL << shift); + + return ApplyAllRegisterValues(); } -bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; } +uint32_t RegisterContextWindows::GetTriggeredHardwareBreakpointSlotId() { + if (!CacheAllRegisterValues()) + return LLDB_INVALID_INDEX32; + + for (unsigned i = 0UL; i < NUM_HARDWARE_BREAKPOINT_SLOTS; i++) + if (m_context.Dr6 & (1ULL << i)) + return i; + + return LLDB_INVALID_INDEX32; +} bool RegisterContextWindows::CacheAllRegisterValues() { Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); @@ -146,3 +173,9 @@ m_context_stale = false; return true; } + +bool RegisterContextWindows::ApplyAllRegisterValues() { + TargetThreadWindows &wthread = static_cast(m_thread); + return ::SetThreadContext( + wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); +} Index: lldb/trunk/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp +++ lldb/trunk/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp @@ -532,9 +532,7 @@ } // Physically update the registers in the target process. - TargetThreadWindows &wthread = static_cast(m_thread); - return ::SetThreadContext( - wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); + return ApplyAllRegisterValues(); } #endif // defined(__x86_64__) || defined(_M_X64) Index: lldb/trunk/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp +++ lldb/trunk/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp @@ -267,9 +267,7 @@ } // Physically update the registers in the target process. - TargetThreadWindows &wthread = static_cast(m_thread); - return ::SetThreadContext( - wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); + return ApplyAllRegisterValues(); } bool RegisterContextWindows_x86::ReadRegisterHelper(