[Lldb-commits] [lldb] r181341 - Add watchpoint support for Linux on 64-bit host.

Matt Kopec Matt.Kopec at intel.com
Tue May 7 12:29:28 PDT 2013


Author: mkopec
Date: Tue May  7 14:29:28 2013
New Revision: 181341

URL: http://llvm.org/viewvc/llvm-project?rev=181341&view=rev
Log:
Add watchpoint support for Linux on 64-bit host.

Modified:
    lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
    lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp
    lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h
    lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp
    lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h
    lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
    lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
    lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
    lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
    lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
    lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
    lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
    lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py
    lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py
    lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py
    lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py
    lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py
    lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py
    lldb/trunk/test/lldbtest.py
    lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py
    lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py
    lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py
    lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Tue May  7 14:29:28 2013
@@ -47,6 +47,11 @@
   #define PTRACE_SETREGSET 0x4205
 #endif
 
+// Support hardware breakpoints in case it has not been defined
+#ifndef TRAP_HWBKPT
+  #define TRAP_HWBKPT 4
+#endif
+
 using namespace lldb_private;
 
 // FIXME: this code is host-dependent with respect to types and
@@ -1415,6 +1420,10 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMo
     case TRAP_BRKPT:
         message = ProcessMessage::Break(pid);
         break;
+
+    case TRAP_HWBKPT:
+        message = ProcessMessage::Watch(pid, (lldb::addr_t)info->si_addr);
+        break;
     }
 
     return message;

Modified: lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp Tue May  7 14:29:28 2013
@@ -15,6 +15,7 @@
 // C++ Includes
 // Other libraries and framework includes
 // Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Target/Process.h"
@@ -229,6 +230,10 @@ POSIXThread::Notify(const ProcessMessage
         BreakNotify(message);
         break;
 
+    case ProcessMessage::eWatchpointMessage:
+        WatchNotify(message);
+        break;
+
     case ProcessMessage::eCrashMessage:
         CrashNotify(message);
         break;
@@ -239,6 +244,58 @@ POSIXThread::Notify(const ProcessMessage
     }
 }
 
+bool
+POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp)
+{
+    bool result = false;
+    if (wp)
+    {
+        addr_t wp_addr = wp->GetLoadAddress();
+        size_t wp_size = wp->GetByteSize();
+        bool wp_read = wp->WatchpointRead();
+        bool wp_write = wp->WatchpointWrite();
+        uint32_t wp_hw_index;
+        lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+        if (reg_ctx_sp.get())
+        {
+            wp_hw_index = reg_ctx_sp->SetHardwareWatchpoint(wp_addr, wp_size,
+                                                            wp_read, wp_write);
+            if (wp_hw_index != LLDB_INVALID_INDEX32)
+            {
+                wp->SetHardwareIndex(wp_hw_index);
+                result = true;
+            }
+        }
+    }
+    return result;
+}
+
+bool
+POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp)
+{
+    bool result = false;
+    if (wp)
+    {
+        lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+        if (reg_ctx_sp.get())
+        {
+            result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex());
+            if (result == true)
+                wp->SetHardwareIndex(LLDB_INVALID_INDEX32);
+        }
+    }
+    return result;
+}
+
+uint32_t
+POSIXThread::NumSupportedHardwareWatchpoints()
+{
+    lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+    if (reg_ctx_sp.get())
+        return reg_ctx_sp->NumSupportedHardwareWatchpoints();
+    return 0;
+}
+
 void
 POSIXThread::BreakNotify(const ProcessMessage &message)
 {
@@ -260,12 +317,50 @@ POSIXThread::BreakNotify(const ProcessMe
     lldb::break_id_t bp_id = bp_site->GetID();
     assert(bp_site && bp_site->ValidForThisThread(this));
 
-    
     m_breakpoint = bp_site;
     SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
 }
 
 void
+POSIXThread::WatchNotify(const ProcessMessage &message)
+{
+    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+    lldb::addr_t halt_addr = message.GetHWAddress();
+    if (log)
+        log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8"
+                     PRIx64, __FUNCTION__, halt_addr);
+
+    RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+    if (reg_ctx)
+    {
+        uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
+        uint32_t wp_idx;
+        for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+        {
+            if (reg_ctx->IsWatchpointHit(wp_idx))
+            {
+                // Clear the watchpoint hit here
+                reg_ctx->ClearWatchpointHits();
+                break;
+            }
+        }
+
+        if (wp_idx == num_hw_wps)
+            return;
+
+        Target &target = GetProcess()->GetTarget();
+        lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx);
+        const WatchpointList &wp_list = target.GetWatchpointList();
+        lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr);
+
+        if (wp_sp)
+            SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this,
+                                                                    wp_sp->GetID()));
+    }
+}
+
+void
 POSIXThread::TraceNotify(const ProcessMessage &message)
 {
     SetStopInfo (StopInfo::CreateStopReasonToTrace(*this));

Modified: lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h Tue May  7 14:29:28 2013
@@ -69,6 +69,15 @@ public:
 
     void Notify(const ProcessMessage &message);
 
+    //--------------------------------------------------------------------------
+    // These methods provide an interface to watchpoints
+    //
+    bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+    bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+    uint32_t NumSupportedHardwareWatchpoints();
+
 private:
     RegisterContextPOSIX *
     GetRegisterContextPOSIX ()
@@ -92,6 +101,7 @@ private:
     GetPrivateStopReason();
 
     void BreakNotify(const ProcessMessage &message);
+    void WatchNotify(const ProcessMessage &message);
     void TraceNotify(const ProcessMessage &message);
     void LimboNotify(const ProcessMessage &message);
     void SignalNotify(const ProcessMessage &message);

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp Tue May  7 14:29:28 2013
@@ -221,6 +221,9 @@ ProcessMessage::PrintKind(Kind kind)
     case eBreakpointMessage:
         str = "eBreakpointMessage";
         break;
+    case eWatchpointMessage:
+        str = "eWatchpointMessage";
+        break;
     case eCrashMessage:
         str = "eCrashMessage";
         break;

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h Tue May  7 14:29:28 2013
@@ -29,6 +29,7 @@ public:
         eSignalDeliveredMessage,
         eTraceMessage,
         eBreakpointMessage,
+        eWatchpointMessage,
         eCrashMessage,
         eNewThreadMessage
     };
@@ -104,6 +105,10 @@ public:
         return ProcessMessage(tid, eBreakpointMessage);
     }
 
+    static ProcessMessage Watch(lldb::tid_t tid, lldb::addr_t wp_addr) {
+        return ProcessMessage(tid, eWatchpointMessage, 0, wp_addr);
+    }
+
     /// Indicates that the thread @p tid crashed.
     static ProcessMessage Crash(lldb::pid_t pid, CrashReason reason,
                                 int signo, lldb::addr_t fault_addr) {
@@ -143,6 +148,11 @@ public:
         return m_addr;
     }
 
+    lldb::addr_t GetHWAddress() const {
+        assert(GetKind() == eWatchpointMessage);
+        return m_addr;
+    }
+
     lldb::tid_t GetChildTID() const {
         assert(GetKind() == eNewThreadMessage);
         return m_child_tid;

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp Tue May  7 14:29:28 2013
@@ -14,6 +14,7 @@
 
 // C++ Includes
 // Other libraries and framework includes
+#include "lldb/Breakpoint/Watchpoint.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/State.h"
@@ -364,6 +365,7 @@ ProcessPOSIX::SendMessage(const ProcessM
 
     case ProcessMessage::eTraceMessage:
     case ProcessMessage::eBreakpointMessage:
+    case ProcessMessage::eWatchpointMessage:
         SetPrivateState(eStateStopped);
         break;
 
@@ -546,6 +548,132 @@ ProcessPOSIX::DisableBreakpointSite(Brea
     return DisableSoftwareBreakpoint(bp_site);
 }
 
+Error
+ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify)
+{
+    Error error;
+    if (wp)
+    {
+        user_id_t watchID = wp->GetID();
+        addr_t addr = wp->GetLoadAddress();
+        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+        if (log)
+            log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")",
+                         watchID);
+        if (wp->IsEnabled())
+        {
+            if (log)
+                log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64
+                            ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
+                            watchID, (uint64_t)addr);
+            return error;
+        }
+
+        bool wp_enabled = true;
+        uint32_t thread_count = m_thread_list.GetSize(false);
+        for (uint32_t i = 0; i < thread_count; ++i)
+        {
+            POSIXThread *thread = static_cast<POSIXThread*>(
+                                  m_thread_list.GetThreadAtIndex(i, false).get());
+            if (thread)
+                wp_enabled &= thread->EnableHardwareWatchpoint(wp);
+            else
+            {
+                wp_enabled = false;
+                break;
+            }
+        }
+        if (wp_enabled)
+        {
+            wp->SetEnabled(true, notify);
+            return error;
+        }
+        else
+        {
+            // Watchpoint enabling failed on at least one
+            // of the threads so roll back all of them
+            DisableWatchpoint(wp, false);
+            error.SetErrorString("Setting hardware watchpoint failed");
+        }
+    }
+    else
+        error.SetErrorString("Watchpoint argument was NULL.");
+    return error;
+}
+
+Error
+ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify)
+{
+    Error error;
+    if (wp)
+    {
+        user_id_t watchID = wp->GetID();
+        addr_t addr = wp->GetLoadAddress();
+        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+        if (log)
+            log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")",
+                        watchID);
+        if (!wp->IsEnabled())
+        {
+            if (log)
+                log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64
+                            ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.",
+                            watchID, (uint64_t)addr);
+            // This is needed (for now) to keep watchpoints disabled correctly
+            wp->SetEnabled(false, notify);
+            return error;
+        }
+
+        if (wp->IsHardware())
+        {
+            bool wp_disabled = true;
+            uint32_t thread_count = m_thread_list.GetSize(false);
+            for (uint32_t i = 0; i < thread_count; ++i)
+            {
+                POSIXThread *thread = static_cast<POSIXThread*>(
+                                      m_thread_list.GetThreadAtIndex(i, false).get());
+                if (thread)
+                    wp_disabled &= thread->DisableHardwareWatchpoint(wp);
+                else
+                    wp_disabled = false;
+            }
+            if (wp_disabled)
+            {
+                wp->SetEnabled(false, notify);
+                return error;
+            }
+            else
+                error.SetErrorString("Disabling hardware watchpoint failed");
+        }
+    }
+    else
+        error.SetErrorString("Watchpoint argument was NULL.");
+    return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num)
+{
+    Error error;
+    POSIXThread *thread = static_cast<POSIXThread*>(
+                          m_thread_list.GetThreadAtIndex(0, false).get());
+    if (thread)
+        num = thread->NumSupportedHardwareWatchpoints();
+    else
+        error.SetErrorString("Process does not exist.");
+    return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after)
+{
+    Error error = GetWatchpointSupportInfo(num);
+    // Watchpoints trigger and halt the inferior after
+    // the corresponding instruction has been executed.
+    after = true;
+    return error;
+}
+
 uint32_t
 ProcessPOSIX::UpdateThreadListIfNeeded()
 {

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h Tue May  7 14:29:28 2013
@@ -108,6 +108,18 @@ public:
     virtual lldb_private::Error
     DisableBreakpointSite(lldb_private::BreakpointSite *bp_site);
 
+    virtual lldb_private::Error
+    EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+    virtual lldb_private::Error
+    DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+    virtual lldb_private::Error
+    GetWatchpointSupportInfo(uint32_t &num);
+
+    virtual lldb_private::Error
+    GetWatchpointSupportInfo(uint32_t &num, bool &after);
+
     virtual uint32_t
     UpdateThreadListIfNeeded();
 

Modified: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp Tue May  7 14:29:28 2013
@@ -25,6 +25,15 @@ do {
     m_register_infos[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg);         \
 } while(false);
 
+#define DR_OFFSET(reg_index)                                                \
+    (offsetof(UserArea, u_debugreg[reg_index]))
+
+#define UPDATE_DR_INFO(reg_index)                                                \
+do {                                                                             \
+    m_register_infos[dr##reg_index].byte_size = sizeof(UserArea::u_debugreg[0]); \
+    m_register_infos[dr##reg_index].byte_offset = DR_OFFSET(reg_index);          \
+} while(false);
+
 typedef struct _GPR
 {
     uint64_t r15;
@@ -155,5 +164,14 @@ RegisterContextLinux_x86_64::UpdateRegis
     UPDATE_I386_GPR_INFO(esp, rsp);
     UPDATE_I386_GPR_INFO(eip, rip);
     UPDATE_I386_GPR_INFO(eflags, rflags);
+
+    UPDATE_DR_INFO(0);
+    UPDATE_DR_INFO(1);
+    UPDATE_DR_INFO(2);
+    UPDATE_DR_INFO(3);
+    UPDATE_DR_INFO(4);
+    UPDATE_DR_INFO(5);
+    UPDATE_DR_INFO(6);
+    UPDATE_DR_INFO(7);
 }
 

Modified: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h Tue May  7 14:29:28 2013
@@ -35,6 +35,20 @@ public:
     /// @return
     ///    True if the operation succeeded and false otherwise.
     virtual bool UpdateAfterBreakpoint() { return true; }
+
+    // Checks to see if a watchpoint specified by hw_index caused the inferior
+    // to stop.
+    virtual bool
+    IsWatchpointHit (uint32_t hw_index) { return false; }
+
+    // Resets any watchpoints that have been hit.
+    virtual bool
+    ClearWatchpointHits () { return false; }
+
+    // Returns the watchpoint address associated with a watchpoint hardware
+    // index.
+    virtual lldb::addr_t
+    GetWatchpointAddress (uint32_t hw_index) {return LLDB_INVALID_ADDRESS; }
 };
 
 #endif // #ifndef liblldb_RegisterContextPOSIX_H_

Modified: lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp Tue May  7 14:29:28 2013
@@ -340,6 +340,11 @@ g_reg_sets[k_num_register_sets] =
       { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i,            \
         LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
 
+#define DEFINE_DR(reg, i)                                              \
+    { #reg#i, NULL, 0, 0, eEncodingUint, eFormatHex,                   \
+      { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+      LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }
+
 #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(RegisterContext_x86_64::FPR))
 
 static RegisterInfo
@@ -439,7 +444,17 @@ g_register_infos[k_num_registers] =
     DEFINE_YMM(ymm, 12),
     DEFINE_YMM(ymm, 13),
     DEFINE_YMM(ymm, 14),
-    DEFINE_YMM(ymm, 15)
+    DEFINE_YMM(ymm, 15),
+
+    // Debug registers for lldb internal use
+    DEFINE_DR(dr, 0),
+    DEFINE_DR(dr, 1),
+    DEFINE_DR(dr, 2),
+    DEFINE_DR(dr, 3),
+    DEFINE_DR(dr, 4),
+    DEFINE_DR(dr, 5),
+    DEFINE_DR(dr, 6),
+    DEFINE_DR(dr, 7)
 };
 
 RegisterInfo *RegisterContext_x86_64::m_register_infos = g_register_infos;
@@ -869,6 +884,27 @@ RegisterContext_x86_64::WriteAllRegister
 }
 
 bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+                                     RegisterValue &value)
+{
+    ProcessMonitor &monitor = GetMonitor();
+    return monitor.ReadRegisterValue(m_thread.GetID(),
+                                     GetRegisterOffset(reg),
+                                     GetRegisterSize(reg),
+                                     value);
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+                                      const RegisterValue &value)
+{
+    ProcessMonitor &monitor = GetMonitor();
+    return monitor.WriteRegisterValue(m_thread.GetID(),
+                                      GetRegisterOffset(reg),
+                                      value);
+}
+
+bool
 RegisterContext_x86_64::UpdateAfterBreakpoint()
 {
     // PC points one byte past the int3 responsible for the breakpoint.
@@ -1178,6 +1214,183 @@ RegisterContext_x86_64::ConvertRegisterK
     return LLDB_INVALID_REGNUM;
 }
 
+uint32_t
+RegisterContext_x86_64::NumSupportedHardwareWatchpoints()
+{
+    // Available debug address registers: dr0, dr1, dr2, dr3
+    return 4;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointVacant(uint32_t hw_index)
+{
+    bool is_vacant = false;
+    RegisterValue value;
+
+    if (ReadRegister(dr7, value))
+    {
+        uint64_t val = value.GetAsUInt64();
+        is_vacant = (val & (3 << 2*hw_index)) == 0;
+    }
+
+    return is_vacant;
+}
+
+static uint32_t
+size_and_rw_bits(size_t size, bool read, bool write)
+{
+    uint32_t rw;
+    if (read) {
+        rw = 0x3; // READ or READ/WRITE
+    } else if (write) {
+        rw = 0x1; // WRITE
+    } else {
+        assert(0 && "read and write cannot both be false");
+    }
+
+    switch (size) {
+    case 1:
+        return rw;
+    case 2:
+        return (0x1 << 2) | rw;
+    case 4:
+        return (0x3 << 2) | rw;
+    case 8:
+        return (0x2 << 2) | rw;
+    default:
+        assert(0 && "invalid size, must be one of 1, 2, 4, or 8");
+    }
+}
+
+uint32_t
+RegisterContext_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size,
+                                              bool read, bool write)
+{
+    const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+    if (num_hw_watchpoints == 0)
+        return LLDB_INVALID_INDEX32;
+
+    if (!(size == 1 || size == 2 || size == 4 || size == 8))
+        return LLDB_INVALID_INDEX32;
+
+    if (read == false && write == false)
+        return LLDB_INVALID_INDEX32;
+
+    uint32_t hw_index = 0;
+    for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+    {
+        if (IsWatchpointVacant(hw_index))
+            break;
+    }
+
+    // Set both dr7 (debug control register) and dri (debug address register).
+
+    // dr7{7-0} encodes the local/gloabl enable bits:
+    //  global enable --. .-- local enable
+    //                  | |
+    //                  v v
+    //      dr0 -> bits{1-0}
+    //      dr1 -> bits{3-2}
+    //      dr2 -> bits{5-4}
+    //      dr3 -> bits{7-6}
+    //
+    // dr7{31-16} encodes the rw/len bits:
+    //  b_x+3, b_x+2, b_x+1, b_x
+    //      where bits{x+1, x} => rw
+    //            0b00: execute, 0b01: write, 0b11: read-or-write,
+    //            0b10: io read-or-write (unused)
+    //      and bits{x+3, x+2} => len
+    //            0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte
+    //
+    //      dr0 -> bits{19-16}
+    //      dr1 -> bits{23-20}
+    //      dr2 -> bits{27-24}
+    //      dr3 -> bits{31-28}
+    if (hw_index < num_hw_watchpoints)
+    {
+        RegisterValue current_dr7_bits;
+
+        if (ReadRegister(dr7, current_dr7_bits))
+        {
+            uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() |
+                                    (1 << (2*hw_index) |
+                                    size_and_rw_bits(size, read, write) <<
+                                    (16+4*hw_index));
+
+            if (WriteRegister(dr0 + hw_index, RegisterValue(addr)) &&
+                WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+                return hw_index;
+        }
+    }
+
+    return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContext_x86_64::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+    if (hw_index < NumSupportedHardwareWatchpoints())
+    {
+        RegisterValue current_dr7_bits;
+
+        if (ReadRegister(dr7, current_dr7_bits))
+        {
+            uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index));
+
+            if (WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+                return true;
+        }
+    }
+
+    return false;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointHit(uint32_t hw_index)
+{
+    bool is_hit = false;
+
+    if (hw_index < NumSupportedHardwareWatchpoints())
+    {
+        RegisterValue value;
+
+        if (ReadRegister(dr6, value))
+        {
+            uint64_t val = value.GetAsUInt64();
+            is_hit = val & (1 << hw_index);
+        }
+    }
+
+    return is_hit;
+}
+
+addr_t
+RegisterContext_x86_64::GetWatchpointAddress(uint32_t hw_index)
+{
+    addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS;
+
+    if (hw_index < NumSupportedHardwareWatchpoints())
+    {
+        if (!IsWatchpointVacant(hw_index))
+        {
+            RegisterValue value;
+
+            if (ReadRegister(dr0 + hw_index, value))
+                wp_monitor_addr = value.GetAsUInt64();
+        }
+    }
+
+    return wp_monitor_addr;
+}
+
+
+bool
+RegisterContext_x86_64::ClearWatchpointHits()
+{
+    return WriteRegister(dr6, RegisterValue((uint64_t)0));
+}
+
 bool
 RegisterContext_x86_64::HardwareSingleStep(bool enable)
 {

Modified: lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h Tue May  7 14:29:28 2013
@@ -110,6 +110,15 @@ enum
     fpu_ymm15,
     k_last_avx = fpu_ymm15,
 
+    dr0,
+    dr1,
+    dr2,
+    dr3,
+    dr4,
+    dr5,
+    dr6,
+    dr7,
+
     k_num_registers,
     k_num_gpr_registers = k_last_gpr - k_first_gpr + 1,
     k_num_fpr_registers = k_last_fpr - k_first_fpr + 1,
@@ -175,15 +184,37 @@ public:
     uint32_t
     ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
 
+    uint32_t
+    NumSupportedHardwareWatchpoints();
+
+    uint32_t
+    SetHardwareWatchpoint(lldb::addr_t, size_t size, bool read, bool write);
+
+    bool
+    ClearHardwareWatchpoint(uint32_t hw_index);
+
     bool
     HardwareSingleStep(bool enable);
 
     bool
     UpdateAfterBreakpoint();
 
+    bool
+    IsWatchpointVacant(uint32_t hw_index);
+
+    bool
+    IsWatchpointHit (uint32_t hw_index);
+
+    lldb::addr_t
+    GetWatchpointAddress (uint32_t hw_index);
+
+    bool
+    ClearWatchpointHits();
+
     //---------------------------------------------------------------------------
     // Generic floating-point registers
     //---------------------------------------------------------------------------
+
     struct MMSReg
     {
         uint8_t bytes[10];
@@ -280,6 +311,12 @@ protected:
     virtual const lldb_private::RegisterInfo *
     GetRegisterInfo();
 
+    virtual bool
+    ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+    virtual bool
+    WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
 private:
     static lldb_private::RegisterInfo *m_register_infos;
 

Modified: lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py Tue May  7 14:29:28 2013
@@ -22,7 +22,6 @@ class HelloWatchpointTestCase(TestBase):
         self.setTearDownCleanup(dictionary=self.d)
         self.hello_watchpoint()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_hello_watchpoint_with_dwarf_using_watchpoint_set(self):
         """Test a simple sequence of watchpoint creation and watchpoint hit."""

Modified: lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py Tue May  7 14:29:28 2013
@@ -20,7 +20,7 @@ class WatchedVariableHitWhenInScopeTestC
     # clearer API to express this.
     #
 
-    @unittest2.expectedFailure
+    @expectedFailureDarwin
     @dsym_test
     def test_watched_var_should_only_hit_when_in_scope_with_dsym(self):
         """Test that a variable watchpoint should only hit when in scope."""
@@ -28,7 +28,7 @@ class WatchedVariableHitWhenInScopeTestC
         self.setTearDownCleanup(dictionary=self.d)
         self.watched_var()
 
-    @unittest2.expectedFailure
+    @expectedFailureDarwin
     @dwarf_test
     def test_watched_var_should_only_hit_when_in_scope_with_dwarf(self):
         """Test that a variable watchpoint should only hit when in scope."""

Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py Tue May  7 14:29:28 2013
@@ -34,7 +34,6 @@ class WatchpointCommandsTestCase(TestBas
         self.setTearDownCleanup(dictionary=self.d)
         self.normal_read_write_watchpoint()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_rw_watchpoint_with_dwarf(self):
         """Test read_write watchpoint and expect to stop two times."""
@@ -50,7 +49,6 @@ class WatchpointCommandsTestCase(TestBas
         self.setTearDownCleanup(dictionary=self.d)
         self.delete_read_write_watchpoint()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_rw_watchpoint_delete_with_dwarf(self):
         """Test delete watchpoint and expect not to stop for watchpoint."""
@@ -66,7 +64,6 @@ class WatchpointCommandsTestCase(TestBas
         self.setTearDownCleanup(dictionary=self.d)
         self.ignore_read_write_watchpoint()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_rw_watchpoint_set_ignore_count_with_dwarf(self):
         """Test watchpoint ignore count and expect to not to stop at all."""
@@ -82,7 +79,6 @@ class WatchpointCommandsTestCase(TestBas
         self.setTearDownCleanup(dictionary=self.d)
         self.read_write_watchpoint_disable_after_first_stop()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_rw_disable_after_first_stop__with_dwarf(self):
         """Test read_write watchpoint but disable it after the first stop."""
@@ -98,7 +94,6 @@ class WatchpointCommandsTestCase(TestBas
         self.setTearDownCleanup(dictionary=self.d)
         self.read_write_watchpoint_disable_then_enable()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_rw_disable_then_enable_with_dwarf(self):
         """Test read_write watchpoint, disable initially, then enable it."""

Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py Tue May  7 14:29:28 2013
@@ -33,7 +33,6 @@ class WatchpointLLDBCommandTestCase(Test
         self.setTearDownCleanup(dictionary=self.d)
         self.watchpoint_command()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_watchpoint_command_with_dwarf(self):
         """Test 'watchpoint command'."""
@@ -49,7 +48,6 @@ class WatchpointLLDBCommandTestCase(Test
         self.setTearDownCleanup(dictionary=self.d)
         self.watchpoint_command_can_disable_a_watchpoint()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_watchpoint_command_can_disable_a_watchpoint_with_dwarf(self):
         """Test that 'watchpoint command' action can disable a watchpoint after it is triggered."""

Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py Tue May  7 14:29:28 2013
@@ -33,7 +33,6 @@ class WatchpointPythonCommandTestCase(Te
         self.setTearDownCleanup(dictionary=self.d)
         self.watchpoint_command()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_watchpoint_command_with_dwarf(self):
         """Test 'watchpoint command'."""

Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py Tue May  7 14:29:28 2013
@@ -33,7 +33,6 @@ class WatchpointConditionCmdTestCase(Tes
         self.setTearDownCleanup(dictionary=self.d)
         self.watchpoint_condition()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_watchpoint_cond_with_dwarf(self):
         """Test watchpoint condition."""

Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py Tue May  7 14:29:28 2013
@@ -18,7 +18,6 @@ class TestWatchpointEvents (TestBase):
         self.buildDsym()
         self.step_over_stepping()
 
-    @expectedFailureLinux # bugzilla 14437
     @python_api_test
     @dwarf_test
     def test_with_dwarf_and_python_api(self):

Modified: lldb/trunk/test/lldbtest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbtest.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/lldbtest.py (original)
+++ lldb/trunk/test/lldbtest.py Tue May  7 14:29:28 2013
@@ -549,6 +549,42 @@ def expectedFailureLinux(bugnumber=None)
               return wrapper
         return expectedFailureLinux_impl
 
+def expectedFailureDarwin(bugnumber=None):
+     if callable(bugnumber):
+        @wraps(bugnumber)
+        def expectedFailureDarwin_easy_wrapper(*args, **kwargs):
+            from unittest2 import case
+            self = args[0]
+            platform = sys.platform
+            try:
+                bugnumber(*args, **kwargs)
+            except Exception:
+                if "darwin" in platform:
+                    raise case._ExpectedFailure(sys.exc_info(),None)
+                else:
+                    raise
+            if "darwin" in platform:
+                raise case._UnexpectedSuccess(sys.exc_info(),None)
+        return expectedFailureDarwin_easy_wrapper
+     else:
+        def expectedFailureDarwin_impl(func):
+              @wraps(func)
+              def wrapper(*args, **kwargs):
+                from unittest2 import case
+                self = args[0]
+                platform = sys.platform
+                try:
+                    func(*args, **kwargs)
+                except Exception:
+                    if "darwin" in platform:
+                        raise case._ExpectedFailure(sys.exc_info(),bugnumber)
+                    else:
+                        raise
+                if "darwin" in platform:
+                    raise case._UnexpectedSuccess(sys.exc_info(),bugnumber)
+              return wrapper
+        return expectedFailureDarwin_impl
+
 def skipOnLinux(func):
     """Decorate the item to skip tests that should be skipped on Linux."""
     if isinstance(func, type) and issubclass(func, unittest2.TestCase):

Modified: lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py (original)
+++ lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py Tue May  7 14:29:28 2013
@@ -28,7 +28,6 @@ class SetWatchpointAPITestCase(TestBase)
         self.buildDsym()
         self.do_set_watchpoint()
 
-    @expectedFailureLinux # bugzilla 14416
     @python_api_test
     @dwarf_test
     def test_watch_val_with_dwarf(self):

Modified: lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py (original)
+++ lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py Tue May  7 14:29:28 2013
@@ -28,7 +28,6 @@ class WatchpointIgnoreCountTestCase(Test
         self.buildDsym()
         self.do_watchpoint_ignore_count()
 
-    @expectedFailureLinux # bugzilla 14416
     @python_api_test
     @dwarf_test
     def test_set_watch_ignore_count_with_dwarf(self):

Modified: lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py (original)
+++ lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py Tue May  7 14:29:28 2013
@@ -28,7 +28,6 @@ class WatchpointIteratorTestCase(TestBas
         self.buildDsym()
         self.do_watchpoint_iter()
 
-    @expectedFailureLinux # bugzilla 14416
     @python_api_test
     @dwarf_test
     def test_watch_iter_with_dwarf(self):

Modified: lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py (original)
+++ lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py Tue May  7 14:29:28 2013
@@ -33,7 +33,6 @@ class WatchpointConditionAPITestCase(Tes
         self.setTearDownCleanup(dictionary=self.d)
         self.watchpoint_condition_api()
 
-    @expectedFailureLinux # bugzilla 14416
     @dwarf_test
     def test_watchpoint_cond_api_with_dwarf(self):
         """Test watchpoint condition API."""





More information about the lldb-commits mailing list