Index: lldb/packages/Python/lldbsuite/test/commands/watchpoints/multiple_threads/TestWatchpointMultipleThreads.py =================================================================== --- lldb/packages/Python/lldbsuite/test/commands/watchpoints/multiple_threads/TestWatchpointMultipleThreads.py +++ 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") Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointsDelayedBreakpointOneWatchpoint.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentBreakpointsDelayedBreakpointOneWatchpoint.py +++ 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. """ Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelaySignalWatch.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelaySignalWatch.py +++ 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.""" Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayWatchBreak.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentDelayWatchBreak.py +++ 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.""" Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentSignalWatch.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentSignalWatch.py +++ 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.""" Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointsOneWatchpoint.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointsOneWatchpoint.py +++ 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. """ Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreak.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreak.py +++ 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.""" Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreakDelay.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchBreakDelay.py +++ 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.""" Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointDelayWatchpointOneBreakpoint.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointDelayWatchpointOneBreakpoint.py +++ 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. """ Index: lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointWithDelayWatchpointThreads.py =================================================================== --- lldb/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentWatchpointWithDelayWatchpointThreads.py +++ 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. """ Index: lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp =================================================================== --- lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ 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, Index: lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h =================================================================== --- lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h +++ lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h @@ -30,6 +30,8 @@ static NativeRegisterContextNetBSD * CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); + virtual Status + CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) = 0; protected: Status DoRegisterSet(int req, void *buf); Index: lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h =================================================================== --- lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h +++ lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h @@ -71,6 +71,10 @@ uint32_t NumSupportedHardwareWatchpoints() override; + Status + CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) + override; + private: // Private member types. enum { GPRegSet, FPRegSet, XStateRegSet, DBRegSet }; Index: lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp =================================================================== --- lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp +++ 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__) Index: lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h =================================================================== --- lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h +++ lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h @@ -62,6 +62,8 @@ void SetRunning(); void SetStepping(); + Status CopyWatchpointsFrom(NativeThreadNetBSD& source); + // Member Variables lldb::StateType m_state; ThreadStopInfo m_stop_info; Index: lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp =================================================================== --- lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -247,3 +247,15 @@ return Status("Clearing hardware breakpoint failed."); } + +Status NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { + Status s = static_cast(GetRegisterContext()) + .CopyHardwareWatchpointsFrom( + static_cast( + 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; +} Index: lldb/test/Shell/Watchpoint/Inputs/thread-dbreg.c =================================================================== --- /dev/null +++ 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; +} Index: lldb/test/Shell/Watchpoint/netbsd-nouserdbregs.test =================================================================== --- /dev/null +++ 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: native && system-netbsd && (target-x86 || target-x86_64) && !dbregs-set +# RUN: %clang %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 Index: lldb/test/Shell/lit.cfg.py =================================================================== --- lldb/test/Shell/lit.cfg.py +++ 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')