diff --git a/lldb/packages/Python/lldbsuite/test/commands/watchpoints/multiple_threads/TestWatchpointMultipleThreads.py b/lldb/packages/Python/lldbsuite/test/commands/watchpoints/multiple_threads/TestWatchpointMultipleThreads.py --- a/lldb/packages/Python/lldbsuite/test/commands/watchpoints/multiple_threads/TestWatchpointMultipleThreads.py +++ b/lldb/packages/Python/lldbsuite/test/commands/watchpoints/multiple_threads/TestWatchpointMultipleThreads.py @@ -18,12 +18,10 @@ NO_DEBUG_INFO_TESTCASE = True main_spec = lldb.SBFileSpec("main.cpp", False) - @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") - @expectedFailureNetBSD def test_watchpoint_after_thread_start(self): """Test that we can hit a watchpoint we set after starting another thread""" self.do_watchpoint_test("After running the thread") diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointsDelayedBreakpointOneWatchpoint.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointsDelayedBreakpointOneWatchpoint.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointsDelayedBreakpointOneWatchpoint.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointsDelayedBreakpointOneWatchpoint.py @@ -16,7 +16,6 @@ @skipIfFreeBSD # timing out on buildbot # Atomic sequences are not supported yet for MIPS in LLDB. @skipIf(triple='^mips') - @expectedFailureNetBSD @add_test_categories(["watchpoint"]) def test(self): """Test a breakpoint, a delayed breakpoint, and one watchpoint thread. """ diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelaySignalWatch.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelaySignalWatch.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelaySignalWatch.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelaySignalWatch.py @@ -15,7 +15,6 @@ @skipIfFreeBSD # timing out on buildbot # Atomic sequences are not supported yet for MIPS in LLDB. @skipIf(triple='^mips') - @expectedFailureNetBSD @add_test_categories(["watchpoint"]) def test(self): """Test a watchpoint and a (1 second delay) signal in multiple threads.""" diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayWatchBreak.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayWatchBreak.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayWatchBreak.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayWatchBreak.py @@ -15,7 +15,6 @@ @skipIfFreeBSD # timing out on buildbot # Atomic sequences are not supported yet for MIPS in LLDB. @skipIf(triple='^mips') - @expectedFailureNetBSD @add_test_categories(["watchpoint"]) def test(self): """Test (1-second delay) watchpoint and a breakpoint in multiple threads.""" diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentSignalWatch.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentSignalWatch.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentSignalWatch.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentSignalWatch.py @@ -15,7 +15,6 @@ @skipIfFreeBSD # timing out on buildbot # Atomic sequences are not supported yet for MIPS in LLDB. @skipIf(triple='^mips') - @expectedFailureNetBSD @add_test_categories(["watchpoint"]) def test(self): """Test a watchpoint and a signal in multiple threads.""" diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointsOneWatchpoint.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointsOneWatchpoint.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointsOneWatchpoint.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointsOneWatchpoint.py @@ -15,7 +15,6 @@ @skipIfFreeBSD # timing out on buildbot # Atomic sequences are not supported yet for MIPS in LLDB. @skipIf(triple='^mips') - @expectedFailureNetBSD @add_test_categories(["watchpoint"]) def test(self): """Test two threads that trigger a breakpoint and one watchpoint thread. """ diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreak.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreak.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreak.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreak.py @@ -15,7 +15,6 @@ @skipIfFreeBSD # timing out on buildbot # Atomic sequences are not supported yet for MIPS in LLDB. @skipIf(triple='^mips') - @expectedFailureNetBSD @add_test_categories(["watchpoint"]) def test(self): """Test watchpoint and a breakpoint in multiple threads.""" diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreakDelay.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreakDelay.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreakDelay.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreakDelay.py @@ -15,7 +15,6 @@ @skipIfFreeBSD # timing out on buildbot # Atomic sequences are not supported yet for MIPS in LLDB. @skipIf(triple='^mips') - @expectedFailureNetBSD @add_test_categories(["watchpoint"]) def test(self): """Test watchpoint and a (1 second delay) breakpoint in multiple threads.""" diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointDelayWatchpointOneBreakpoint.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointDelayWatchpointOneBreakpoint.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointDelayWatchpointOneBreakpoint.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointDelayWatchpointOneBreakpoint.py @@ -15,7 +15,6 @@ @skipIfFreeBSD # timing out on buildbot # Atomic sequences are not supported yet for MIPS in LLDB. @skipIf(triple='^mips') - @expectedFailureNetBSD @add_test_categories(["watchpoint"]) def test(self): """Test two threads that trigger a watchpoint (one with a 1 second delay) and one breakpoint thread. """ diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointWithDelayWatchpointThreads.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointWithDelayWatchpointThreads.py --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointWithDelayWatchpointThreads.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointWithDelayWatchpointThreads.py @@ -15,7 +15,6 @@ @skipIfFreeBSD # timing out on buildbot # Atomic sequences are not supported yet for MIPS in LLDB. @skipIf(triple='^mips') - @expectedFailureNetBSD @add_test_categories(["watchpoint"]) def test(self): """Test two threads that trigger a watchpoint where one thread has a 1 second delay. """ diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp --- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -272,12 +272,21 @@ } switch (pst.pe_report_event) { - case PTRACE_LWP_CREATE: + case PTRACE_LWP_CREATE: { LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid, pst.pe_lwp); - AddThread(pst.pe_lwp); - break; + NativeThreadNetBSD& t = AddThread(pst.pe_lwp); + error = t.CopyWatchpointsFrom( + static_cast(*GetCurrentThread())); + if (error.Fail()) { + LLDB_LOG(log, + "failed to copy watchpoints to new thread {0}: {1}", + pst.pe_lwp, error); + SetState(StateType::eStateInvalid); + return; + } + } break; case PTRACE_LWP_EXIT: LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid, diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h @@ -11,12 +11,13 @@ #include "lldb/Host/common/NativeThreadProtocol.h" -#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" namespace lldb_private { namespace process_netbsd { +class NativeProcessNetBSD; + class NativeRegisterContextNetBSD : public NativeRegisterContextRegisterInfo { public: NativeRegisterContextNetBSD(NativeThreadProtocol &native_thread, @@ -30,6 +31,8 @@ static NativeRegisterContextNetBSD * CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); + virtual Status + CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) = 0; protected: Status DoRegisterSet(int req, void *buf); diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp @@ -8,6 +8,8 @@ #include "NativeRegisterContextNetBSD.h" +#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" + #include "lldb/Host/common/NativeProcessProtocol.h" using namespace lldb_private; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h @@ -71,6 +71,9 @@ uint32_t NumSupportedHardwareWatchpoints() override; + Status + CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) override; + private: // Private member types. enum { GPRegSet, FPRegSet, XStateRegSet, DBRegSet }; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp @@ -988,4 +988,19 @@ return 4; } +Status NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom( + NativeRegisterContextNetBSD &source) { + auto &r_source = static_cast(source); + Status res = r_source.ReadRegisterSet(DBRegSet); + if (!res.Fail()) { + // copy dbregs only if any watchpoints were set + if ((r_source.m_dbr_x86_64.dr[7] & 0xFF) == 0) + return res; + + m_dbr_x86_64 = r_source.m_dbr_x86_64; + res = WriteRegisterSet(DBRegSet); + } + return res; +} + #endif // defined(__x86_64__) diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h --- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h @@ -11,6 +11,8 @@ #include "lldb/Host/common/NativeThreadProtocol.h" +#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h" + #include #include #include @@ -34,7 +36,7 @@ bool GetStopReason(ThreadStopInfo &stop_info, std::string &description) override; - NativeRegisterContext& GetRegisterContext() override; + NativeRegisterContextNetBSD &GetRegisterContext() override; Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) override; @@ -62,10 +64,12 @@ void SetRunning(); void SetStepping(); + Status CopyWatchpointsFrom(NativeThreadNetBSD& source); + // Member Variables lldb::StateType m_state; ThreadStopInfo m_stop_info; - std::unique_ptr m_reg_context_up; + std::unique_ptr m_reg_context_up; std::string m_stop_description; using WatchpointIndexMap = std::map; WatchpointIndexMap m_watchpoint_index_map; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp --- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -221,9 +221,9 @@ llvm_unreachable("unhandled StateType!"); } -NativeRegisterContext& NativeThreadNetBSD::GetRegisterContext() { +NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { assert(m_reg_context_up); -return *m_reg_context_up; + return *m_reg_context_up; } Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, @@ -284,3 +284,13 @@ return Status("Clearing hardware breakpoint failed."); } + +Status NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { + Status s = GetRegisterContext().CopyHardwareWatchpointsFrom( + source.GetRegisterContext()); + if (!s.Fail()) { + m_watchpoint_index_map = source.m_watchpoint_index_map; + m_hw_break_index_map = source.m_hw_break_index_map; + } + return s; +} diff --git a/lldb/test/Shell/Watchpoint/Inputs/thread-dbreg.c b/lldb/test/Shell/Watchpoint/Inputs/thread-dbreg.c new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Watchpoint/Inputs/thread-dbreg.c @@ -0,0 +1,23 @@ +#include + +int g_watchme = 0; + +void *thread_func(void *arg) { + /* watchpoint trigger from subthread */ + g_watchme = 2; + return 0; +} + +int main() { + pthread_t thread; + if (pthread_create(&thread, 0, thread_func, 0)) + return 1; + + /* watchpoint trigger from main thread */ + g_watchme = 1; + + if (pthread_join(thread, 0)) + return 2; + + return 0; +} diff --git a/lldb/test/Shell/Watchpoint/netbsd-nouserdbregs.test b/lldb/test/Shell/Watchpoint/netbsd-nouserdbregs.test new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Watchpoint/netbsd-nouserdbregs.test @@ -0,0 +1,22 @@ +# Check that 'watchpoint set' errors out gracefully when we can't set dbregs +# and that new threads are monitored correctly even though we can't copy dbregs. + +# REQUIRES: system-netbsd && (target-x86 || target-x86_64) && !dbregs-set +# RUN: %clang_host %p/Inputs/thread-dbreg.c -pthread -g -o %t.out +# RUN: %lldb -b -o 'settings set interpreter.stop-command-source-on-error false' -s %s %t.out 2>&1 | FileCheck %s + +settings show interpreter.stop-command-source-on-error +# CHECK: interpreter.stop-command-source-on-error (boolean) = false + +b main +# CHECK: Breakpoint {{[0-9]+}}: where = {{.*}}`main +b thread_func +# CHECK: Breakpoint {{[0-9]+}}: where = {{.*}}`thread_func +run +# CHECK: stop reason = breakpoint +watchpoint set variable g_watchme +# CHECK: error: Watchpoint creation failed +cont +# CHECK: stop reason = breakpoint +cont +# CHECK: Process {{[0-9]+}} exited with status = 0 diff --git a/lldb/test/Shell/lit.cfg.py b/lldb/test/Shell/lit.cfg.py --- a/lldb/test/Shell/lit.cfg.py +++ b/lldb/test/Shell/lit.cfg.py @@ -5,6 +5,7 @@ import re import shutil import site +import subprocess import sys import lit.formats @@ -103,3 +104,17 @@ if find_executable('xz') != None: config.available_features.add('xz') + +# NetBSD permits setting dbregs either if one is root +# or if user_set_dbregs is enabled +can_set_dbregs = True +if platform.system() == 'NetBSD' and os.geteuid() != 0: + try: + output = subprocess.check_output(["/sbin/sysctl", "-n", + "security.models.extensions.user_set_dbregs"]).decode().strip() + if output != "1": + can_set_dbregs = False + except subprocess.CalledProcessError: + can_set_dbregs = False +if can_set_dbregs: + config.available_features.add('dbregs-set')