Index: lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h =================================================================== --- lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h +++ lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h @@ -100,10 +100,13 @@ ClearAllHardwareWatchpoints (); virtual Error - IsWatchpointHit (uint8_t wp_index); + IsWatchpointHit(uint32_t wp_index, bool &is_hit); virtual Error - IsWatchpointVacant (uint32_t wp_index); + GetWatchpointHitIndex(uint32_t &wp_index); + + virtual Error + IsWatchpointVacant (uint32_t wp_index, bool &is_vacant); virtual lldb::addr_t GetWatchpointAddress (uint32_t wp_index); Index: lldb/trunk/source/Host/common/NativeRegisterContext.cpp =================================================================== --- lldb/trunk/source/Host/common/NativeRegisterContext.cpp +++ lldb/trunk/source/Host/common/NativeRegisterContext.cpp @@ -302,14 +302,23 @@ } Error -NativeRegisterContext::IsWatchpointHit (uint8_t wp_index) +NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit) { + is_hit = false; return Error ("not implemented"); } Error -NativeRegisterContext::IsWatchpointVacant (uint32_t wp_index) +NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index) { + wp_index = LLDB_INVALID_INDEX32; + return Error ("not implemented"); +} + +Error +NativeRegisterContext::IsWatchpointVacant (uint32_t wp_index, bool &is_vacant) +{ + is_vacant = false; return Error ("not implemented"); } Index: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h +++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -296,6 +296,15 @@ MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid); void + MonitorTrace(lldb::pid_t pid, NativeThreadProtocolSP thread_sp); + + void + MonitorBreakpoint(lldb::pid_t pid, NativeThreadProtocolSP thread_sp); + + void + MonitorWatchpoint(lldb::pid_t pid, NativeThreadProtocolSP thread_sp, uint32_t wp_index); + + void MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool exited); #if 0 Index: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -39,6 +39,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessLaunchInfo.h" +#include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/PseudoTerminal.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" @@ -2251,93 +2252,31 @@ } case 0: - case TRAP_TRACE: - // We receive this on single stepping. - if (log) - log->Printf ("NativeProcessLinux::%s() received trace event, pid = %" PRIu64 " (single stepping)", __FUNCTION__, pid); - + case TRAP_TRACE: // We receive this on single stepping. + case TRAP_HWBKPT: // We receive this on watchpoint hit if (thread_sp) { - std::static_pointer_cast (thread_sp)->SetStoppedByTrace (); - } - - // This thread is currently stopped. - NotifyThreadStop (pid); - - // Here we don't have to request the rest of the threads to stop or request a deferred stop. - // This would have already happened at the time the Resume() with step operation was signaled. - // At this point, we just need to say we stopped, and the deferred notifcation will fire off - // once all running threads have checked in as stopped. - SetCurrentThreadID (pid); - // Tell the process we have a stop (from software breakpoint). - CallAfterRunningThreadsStop (pid, - [=] (lldb::tid_t signaling_tid) - { - SetState (StateType::eStateStopped, true); - }); - break; - - case SI_KERNEL: - case TRAP_BRKPT: - if (log) - log->Printf ("NativeProcessLinux::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid); - - // This thread is currently stopped. - NotifyThreadStop (pid); - - // Mark the thread as stopped at breakpoint. - if (thread_sp) - { - std::static_pointer_cast (thread_sp)->SetStoppedByBreakpoint (); - Error error = FixupBreakpointPCAsNeeded (thread_sp); - if (error.Fail ()) + // If a watchpoint was hit, report it + uint32_t wp_index; + Error error = thread_sp->GetRegisterContext()->GetWatchpointHitIndex(wp_index); + if (error.Fail() && log) + log->Printf("NativeProcessLinux::%s() " + "received error while checking for watchpoint hits, " + "pid = %" PRIu64 " error = %s", + __FUNCTION__, pid, error.AsCString()); + if (wp_index != LLDB_INVALID_INDEX32) { - if (log) - log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " fixup: %s", __FUNCTION__, pid, error.AsCString ()); + MonitorWatchpoint(pid, thread_sp, wp_index); + break; } } - else - { - if (log) - log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 ": warning, cannot process software breakpoint since no thread metadata", __FUNCTION__, pid); - } - - - // We need to tell all other running threads before we notify the delegate about this stop. - CallAfterRunningThreadsStop (pid, - [=](lldb::tid_t deferred_notification_tid) - { - SetCurrentThreadID (deferred_notification_tid); - // Tell the process we have a stop (from software breakpoint). - SetState (StateType::eStateStopped, true); - }); + // Otherwise, report step over + MonitorTrace(pid, thread_sp); break; - case TRAP_HWBKPT: - if (log) - log->Printf ("NativeProcessLinux::%s() received watchpoint event, pid = %" PRIu64, __FUNCTION__, pid); - - // This thread is currently stopped. - NotifyThreadStop (pid); - - // Mark the thread as stopped at watchpoint. - // The address is at (lldb::addr_t)info->si_addr if we need it. - if (thread_sp) - std::static_pointer_cast (thread_sp)->SetStoppedByWatchpoint (); - else - { - if (log) - log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ": warning, cannot process hardware breakpoint since no thread metadata", __FUNCTION__, GetID (), pid); - } - - // We need to tell all other running threads before we notify the delegate about this stop. - CallAfterRunningThreadsStop (pid, - [=](lldb::tid_t deferred_notification_tid) - { - SetCurrentThreadID (deferred_notification_tid); - // Tell the process we have a stop (from hardware breakpoint). - SetState (StateType::eStateStopped, true); - }); + case SI_KERNEL: + case TRAP_BRKPT: + MonitorBreakpoint(pid, thread_sp); break; case SIGTRAP: @@ -2371,6 +2310,98 @@ } void +NativeProcessLinux::MonitorTrace(lldb::pid_t pid, NativeThreadProtocolSP thread_sp) +{ + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("NativeProcessLinux::%s() received trace event, pid = %" PRIu64 " (single stepping)", + __FUNCTION__, pid); + + if (thread_sp) + std::static_pointer_cast(thread_sp)->SetStoppedByTrace(); + + // This thread is currently stopped. + NotifyThreadStop(pid); + + // Here we don't have to request the rest of the threads to stop or request a deferred stop. + // This would have already happened at the time the Resume() with step operation was signaled. + // At this point, we just need to say we stopped, and the deferred notifcation will fire off + // once all running threads have checked in as stopped. + SetCurrentThreadID(pid); + // Tell the process we have a stop (from software breakpoint). + CallAfterRunningThreadsStop(pid, + [=](lldb::tid_t signaling_tid) + { + SetState(StateType::eStateStopped, true); + }); +} + +void +NativeProcessLinux::MonitorBreakpoint(lldb::pid_t pid, NativeThreadProtocolSP thread_sp) +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("NativeProcessLinux::%s() received breakpoint event, pid = %" PRIu64, + __FUNCTION__, pid); + + // This thread is currently stopped. + NotifyThreadStop(pid); + + // Mark the thread as stopped at breakpoint. + if (thread_sp) + { + std::static_pointer_cast(thread_sp)->SetStoppedByBreakpoint(); + Error error = FixupBreakpointPCAsNeeded(thread_sp); + if (error.Fail()) + if (log) + log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 " fixup: %s", + __FUNCTION__, pid, error.AsCString()); + } + else + if (log) + log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 ": " + "warning, cannot process software breakpoint since no thread metadata", + __FUNCTION__, pid); + + + // We need to tell all other running threads before we notify the delegate about this stop. + CallAfterRunningThreadsStop(pid, + [=](lldb::tid_t deferred_notification_tid) + { + SetCurrentThreadID(deferred_notification_tid); + // Tell the process we have a stop (from software breakpoint). + SetState(StateType::eStateStopped, true); + }); +} + +void +NativeProcessLinux::MonitorWatchpoint(lldb::pid_t pid, NativeThreadProtocolSP thread_sp, uint32_t wp_index) +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("NativeProcessLinux::%s() received watchpoint event, " + "pid = %" PRIu64 ", wp_index = %" PRIu32, + __FUNCTION__, pid, wp_index); + + // This thread is currently stopped. + NotifyThreadStop(pid); + + // Mark the thread as stopped at watchpoint. + // The address is at (lldb::addr_t)info->si_addr if we need it. + lldbassert(thread_sp && "thread_sp cannot be NULL"); + std::static_pointer_cast(thread_sp)->SetStoppedByWatchpoint(wp_index); + + // We need to tell all other running threads before we notify the delegate about this stop. + CallAfterRunningThreadsStop(pid, + [=](lldb::tid_t deferred_notification_tid) + { + SetCurrentThreadID(deferred_notification_tid); + // Tell the process we have a stop (from watchpoint). + SetState(StateType::eStateStopped, true); + }); +} + +void NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool exited) { assert (info && "null info"); Index: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h +++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h @@ -91,10 +91,10 @@ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override; Error - IsWatchpointHit (uint8_t wp_index) override; + IsWatchpointHit (uint32_t wp_index, bool &is_hit) override; Error - IsWatchpointVacant (uint32_t wp_index) override; + IsWatchpointVacant (uint32_t wp_index, bool &is_vacant) override; bool ClearHardwareWatchpoint (uint32_t wp_index) override; Index: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -155,19 +155,17 @@ } Error -NativeRegisterContextLinux_mips64::IsWatchpointHit (uint8_t wp_index) +NativeRegisterContextLinux_mips64::IsWatchpointHit (uint32_t wp_index, bool &is_hit) { - Error error; - error.SetErrorString ("MIPS TODO: NativeRegisterContextLinux_mips64::IsWatchpointHit not implemented"); - return error; + is_hit = false; + return Error("MIPS TODO: NativeRegisterContextLinux_mips64::IsWatchpointHit not implemented"); } Error -NativeRegisterContextLinux_mips64::IsWatchpointVacant (uint32_t wp_index) +NativeRegisterContextLinux_mips64::IsWatchpointVacant (uint32_t wp_index, bool &is_vacant) { - Error error; - error.SetErrorString ("MIPS TODO: NativeRegisterContextLinux_mips64::IsWatchpointVacant not implemented"); - return error; + is_vacant = false; + return Error("MIPS TODO: NativeRegisterContextLinux_mips64::IsWatchpointVacant not implemented"); } bool Index: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h @@ -46,10 +46,13 @@ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override; Error - IsWatchpointHit(uint8_t wp_index) override; + IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; Error - IsWatchpointVacant(uint32_t wp_index) override; + GetWatchpointHitIndex(uint32_t &wp_index) override; + + Error + IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; bool ClearHardwareWatchpoint(uint32_t wp_index) override; Index: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -9,6 +9,7 @@ #include "NativeRegisterContextLinux_x86_64.h" +#include "lldb/Core/Log.h" #include "lldb/lldb-private-forward.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Error.h" @@ -1046,39 +1047,61 @@ } Error -NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint8_t wp_index) +NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint32_t wp_index, bool &is_hit) { if (wp_index >= NumSupportedHardwareWatchpoints()) - return Error ("Watchpoint index out of range"); + return Error("Watchpoint index out of range"); RegisterValue reg_value; Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value); - if (error.Fail()) return error; + if (error.Fail()) + { + is_hit = false; + return error; + } uint64_t status_bits = reg_value.GetAsUInt64(); - bool is_hit = status_bits & (1 << wp_index); - - error.SetError (!is_hit, lldb::eErrorTypeInvalid); + is_hit = status_bits & (1 << wp_index); return error; } Error -NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index) +NativeRegisterContextLinux_x86_64::GetWatchpointHitIndex(uint32_t &wp_index) { + uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); + for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) + { + bool is_hit; + Error error = IsWatchpointHit(wp_index, is_hit); + if (error.Fail()) { + wp_index = LLDB_INVALID_INDEX32; + return error; + } else if (is_hit) { + return error; + } + } + wp_index = LLDB_INVALID_INDEX32; + return Error(); +} + +Error +NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) { if (wp_index >= NumSupportedHardwareWatchpoints()) return Error ("Watchpoint index out of range"); RegisterValue reg_value; Error error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); - if (error.Fail()) return error; + if (error.Fail()) + { + is_vacant = false; + return error; + } uint64_t control_bits = reg_value.GetAsUInt64(); - bool is_vacant = !(control_bits & (1 << (2 * wp_index))); - - error.SetError (!is_vacant, lldb::eErrorTypeInvalid); + is_vacant = !(control_bits & (1 << (2 * wp_index))); return error; } @@ -1096,8 +1119,10 @@ if (size != 1 && size != 2 && size != 4 && size != 8) return Error ("Invalid size for watchpoint"); - Error error = IsWatchpointVacant (wp_index); + bool is_vacant; + Error error = IsWatchpointVacant (wp_index, is_vacant); if (error.Fail()) return error; + if (!is_vacant) return Error("Watchpoint index not vacant"); RegisterValue reg_value; error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); @@ -1184,14 +1209,24 @@ NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint( lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) - if (IsWatchpointVacant(wp_index).Success()) + { + bool is_vacant; + Error error = IsWatchpointVacant(wp_index, is_vacant); + if (is_vacant) { - if (SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index).Fail()) - continue; - return wp_index; + error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index); + if (error.Success()) + return wp_index; } + if (error.Fail() && log) + { + log->Printf("NativeRegisterContextLinux_x86_64::%s Error: %s", + __FUNCTION__, error.AsCString()); + } + } return LLDB_INVALID_INDEX32; } Index: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h +++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h @@ -76,7 +76,7 @@ SetStoppedByBreakpoint (); void - SetStoppedByWatchpoint (); + SetStoppedByWatchpoint (uint32_t wp_index); bool IsStoppedAtBreakpoint (); Index: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -22,6 +22,7 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/HostNativeThread.h" +#include "lldb/Utility/LLDBAssert.h" #include "lldb/lldb-enumerations.h" #include "llvm/ADT/SmallString.h" @@ -379,53 +380,23 @@ } void -NativeThreadLinux::SetStoppedByWatchpoint () +NativeThreadLinux::SetStoppedByWatchpoint (uint32_t wp_index) { - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - if (log) - { - NativeProcessProtocolSP process_sp = m_process_wp.lock (); - if (process_sp) - pid = process_sp->GetID (); - } - const StateType new_state = StateType::eStateStopped; MaybeLogStateChange (new_state); m_state = new_state; - - NativeRegisterContextSP reg_ctx = GetRegisterContext (); - const uint32_t num_hw_watchpoints = reg_ctx->NumSupportedHardwareWatchpoints (); - m_stop_description.clear (); - for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) - { - if (reg_ctx->IsWatchpointHit (wp_index).Success()) - { - if (log) - log->Printf ("NativeThreadLinux:%s (pid=%" PRIu64 ", tid=%" PRIu64 ") watchpoint found with idx: %u", - __FUNCTION__, pid, GetID (), wp_index); - - std::ostringstream ostr; - ostr << reg_ctx->GetWatchpointAddress (wp_index) << " " << wp_index; - m_stop_description = ostr.str(); - - m_stop_info.reason = StopReason::eStopReasonWatchpoint; - m_stop_info.details.signal.signo = SIGTRAP; - return; - } - } - // The process reported a watchpoint was hit, but we haven't found the - // watchpoint. Assume that a stopped by trace is reported as a hardware - // watchpoint what happens on some linux kernels (e.g.: android-arm64 - // platfrom-21). + lldbassert(wp_index != LLDB_INVALID_INDEX32 && + "wp_index cannot be invalid"); - if (log) - log->Printf ("NativeThreadLinux:%s (pid=%" PRIu64 ", tid=%" PRIu64 ") none of the watchpoint was hit.", - __FUNCTION__, pid, GetID ()); + std::ostringstream ostr; + ostr << GetRegisterContext()->GetWatchpointAddress(wp_index) << " "; + ostr << wp_index; + m_stop_description = ostr.str(); - SetStoppedByTrace (); + m_stop_info.reason = StopReason::eStopReasonWatchpoint; + m_stop_info.details.signal.signo = SIGTRAP; } bool Index: lldb/trunk/test/functionalities/watchpoint/step_over_watchpoint/Makefile =================================================================== --- lldb/trunk/test/functionalities/watchpoint/step_over_watchpoint/Makefile +++ lldb/trunk/test/functionalities/watchpoint/step_over_watchpoint/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules Index: lldb/trunk/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py =================================================================== --- lldb/trunk/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py +++ lldb/trunk/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py @@ -0,0 +1,124 @@ +"""Test stepping over watchpoints.""" + +import unittest2 +import lldb +import lldbutil +from lldbtest import * + + +class TestStepOverWatchpoint(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def getCategories(self): + return ['basic_process'] + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dsym_test + def test_with_dsym(self): + """Test stepping over watchpoints.""" + self.buildDsym() + self.step_over_watchpoint() + + @dwarf_test + def test_with_dwarf(self): + """Test stepping over watchpoints.""" + self.buildDwarf() + self.step_over_watchpoint() + + def setUp(self): + TestBase.setUp(self) + + def step_inst_for_watchpoint(self, wp_id): + watchpoint_hit = False + current_line = self.frame().GetLineEntry().GetLine() + while self.frame().GetLineEntry().GetLine() == current_line: + self.thread().StepInstruction(False) # step_over=False + stop_reason = self.thread().GetStopReason() + if stop_reason == lldb.eStopReasonWatchpoint: + self.assertFalse(watchpoint_hit, "Watchpoint already hit.") + expected_stop_desc = "watchpoint %d" % wp_id + actual_stop_desc = self.thread().GetStopDescription(20) + self.assertTrue(actual_stop_desc == expected_stop_desc, + "Watchpoint ID didn't match.") + watchpoint_hit = True + else: + self.assertTrue(stop_reason == lldb.eStopReasonPlanComplete, + STOPPED_DUE_TO_STEP_IN) + self.assertTrue(watchpoint_hit, "Watchpoint never hit.") + + def step_over_watchpoint(self): + """Test stepping over watchpoints.""" + exe = os.path.join(os.getcwd(), 'a.out') + + target = self.dbg.CreateTarget(exe) + self.assertTrue(self.target, VALID_TARGET) + + lldbutil.run_break_set_by_symbol(self, 'main') + + process = target.LaunchSimple(None, None, + self.get_process_working_directory()) + self.assertTrue(process.IsValid(), PROCESS_IS_VALID) + self.assertTrue(process.GetState() == lldb.eStateStopped, + PROCESS_STOPPED) + + thread = lldbutil.get_stopped_thread(process, + lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid(), "Failed to get thread.") + + frame = thread.GetFrameAtIndex(0) + self.assertTrue(frame.IsValid(), "Failed to get frame.") + + read_value = frame.FindValue('g_watch_me_read', + lldb.eValueTypeVariableGlobal) + self.assertTrue(read_value.IsValid(), "Failed to find read value.") + + error = lldb.SBError() + + # resolve_location=True, read=True, write=False + read_watchpoint = read_value.Watch(True, True, False, error) + self.assertTrue(error.Success(), + "Error while setting watchpoint: %s" % + error.GetCString()) + self.assertTrue(read_watchpoint, "Failed to set read watchpoint.") + + write_value = frame.FindValue('g_watch_me_write', + lldb.eValueTypeVariableGlobal) + self.assertTrue(write_value, "Failed to find write value.") + + # resolve_location=True, read=False, write=True + write_watchpoint = write_value.Watch(True, False, True, error) + self.assertTrue(read_watchpoint, "Failed to set write watchpoint.") + self.assertTrue(error.Success(), + "Error while setting watchpoint: %s" % + error.GetCString()) + + thread.StepOver() + self.assertTrue(thread.GetStopReason() == lldb.eStopReasonWatchpoint, + STOPPED_DUE_TO_WATCHPOINT) + self.assertTrue(thread.GetStopDescription(20) == 'watchpoint 1') + + process.Continue() + self.assertTrue(process.GetState() == lldb.eStateStopped, + PROCESS_STOPPED) + self.assertTrue(thread.GetStopDescription(20) == 'step over') + + self.step_inst_for_watchpoint(1) + + thread.StepOver() + self.assertTrue(thread.GetStopReason() == lldb.eStopReasonWatchpoint, + STOPPED_DUE_TO_WATCHPOINT) + self.assertTrue(thread.GetStopDescription(20) == 'watchpoint 2') + + process.Continue() + self.assertTrue(process.GetState() == lldb.eStateStopped, + PROCESS_STOPPED) + self.assertTrue(thread.GetStopDescription(20) == 'step over') + + self.step_inst_for_watchpoint(2) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: lldb/trunk/test/functionalities/watchpoint/step_over_watchpoint/main.c =================================================================== --- lldb/trunk/test/functionalities/watchpoint/step_over_watchpoint/main.c +++ lldb/trunk/test/functionalities/watchpoint/step_over_watchpoint/main.c @@ -0,0 +1,19 @@ +char g_watch_me_read; +char g_watch_me_write; +char g_temp; + +void watch_read() { + g_temp = g_watch_me_read; +} + +void watch_write() { + g_watch_me_write = g_temp; +} + +int main() { + watch_read(); + g_temp = g_watch_me_read; + watch_write(); + g_watch_me_write = g_temp; + return 0; +}