diff options
13 files changed, 359 insertions, 152 deletions
diff --git a/lldb/include/lldb/Host/common/NativeRegisterContext.h b/lldb/include/lldb/Host/common/NativeRegisterContext.h index b2d30c2a271..9197e6bd72f 100644 --- a/lldb/include/lldb/Host/common/NativeRegisterContext.h +++ b/lldb/include/lldb/Host/common/NativeRegisterContext.h @@ -100,10 +100,13 @@ public:      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); diff --git a/lldb/source/Host/common/NativeRegisterContext.cpp b/lldb/source/Host/common/NativeRegisterContext.cpp index b8f811a6df8..77f091125cc 100644 --- a/lldb/source/Host/common/NativeRegisterContext.cpp +++ b/lldb/source/Host/common/NativeRegisterContext.cpp @@ -302,14 +302,23 @@ NativeRegisterContext::ClearAllHardwareWatchpoints ()  }  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");  } diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp index b0a2d6c5c4b..fd3a62eab42 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/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 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)      }      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<NativeThreadLinux> (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<NativeThreadLinux> (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<NativeThreadLinux> (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 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)  }  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<NativeThreadLinux>(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<NativeThreadLinux>(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<NativeThreadLinux>(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"); diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h index a2ffd6cb68b..07220e97e3a 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -296,6 +296,15 @@ namespace lldb_private          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 diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp index 67363ca6bbc..3d798e6e0f9 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -155,19 +155,17 @@ NativeRegisterContextLinux_mips64::WriteAllRegisterValues (const lldb::DataBuffe  }  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 diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h index b7833438ae0..35218b7eb58 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h @@ -91,10 +91,10 @@ namespace lldb_private          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; diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp index fa6dfd64b88..06ad5f296ec 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/lldb/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 @@ NativeRegisterContextLinux_x86_64::WriteGPR()  }  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 @@ NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex(      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 @@ uint32_t  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;  } diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h index 0e9d721959b..e183118e8d4 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h @@ -46,10 +46,13 @@ namespace lldb_private          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; diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp index 148f55f8033..51597f8dd17 100644 --- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ b/lldb/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 @@ NativeThreadLinux::SetStoppedByBreakpoint ()  }  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 diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h index 2519b5b1da0..c77dcbe093f 100644 --- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h @@ -76,7 +76,7 @@ namespace lldb_private          SetStoppedByBreakpoint ();          void -        SetStoppedByWatchpoint (); +        SetStoppedByWatchpoint (uint32_t wp_index);          bool          IsStoppedAtBreakpoint (); diff --git a/lldb/test/functionalities/watchpoint/step_over_watchpoint/Makefile b/lldb/test/functionalities/watchpoint/step_over_watchpoint/Makefile new file mode 100644 index 00000000000..b09a579159d --- /dev/null +++ b/lldb/test/functionalities/watchpoint/step_over_watchpoint/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py b/lldb/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py new file mode 100644 index 00000000000..30947f4a3f9 --- /dev/null +++ b/lldb/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() diff --git a/lldb/test/functionalities/watchpoint/step_over_watchpoint/main.c b/lldb/test/functionalities/watchpoint/step_over_watchpoint/main.c new file mode 100644 index 00000000000..2d87d9a2f73 --- /dev/null +++ b/lldb/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; +}  | 

