[Lldb-commits] [lldb] r237419 - This patch adds support for setting/clearing hardware watchpoints and breakpoints on AArch64 (Arm v8) 64-bit hardware.

Omair Javaid omair.javaid at linaro.org
Thu May 14 23:30:00 PDT 2015


Author: omjavaid
Date: Fri May 15 01:29:58 2015
New Revision: 237419

URL: http://llvm.org/viewvc/llvm-project?rev=237419&view=rev
Log:
This patch adds support for setting/clearing hardware watchpoints and breakpoints on AArch64 (Arm v8) 64-bit hardware.

http://reviews.llvm.org/D9706


Modified:
    lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h
    lldb/trunk/source/Host/common/NativeRegisterContext.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
    lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
    lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h

Modified: lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h?rev=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h (original)
+++ lldb/trunk/include/lldb/Host/common/NativeRegisterContext.h Fri May 15 01:29:58 2015
@@ -103,7 +103,7 @@ public:
     IsWatchpointHit(uint32_t wp_index, bool &is_hit);
 
     virtual Error
-    GetWatchpointHitIndex(uint32_t &wp_index);
+    GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr);
 
     virtual Error
     IsWatchpointVacant (uint32_t wp_index, bool &is_vacant);

Modified: lldb/trunk/source/Host/common/NativeRegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeRegisterContext.cpp?rev=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/NativeRegisterContext.cpp (original)
+++ lldb/trunk/source/Host/common/NativeRegisterContext.cpp Fri May 15 01:29:58 2015
@@ -309,7 +309,7 @@ NativeRegisterContext::IsWatchpointHit(u
 }
 
 Error
-NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index)
+NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
 {
     wp_index = LLDB_INVALID_INDEX32;
     return Error ("not implemented");

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Fri May 15 01:29:58 2015
@@ -762,6 +762,47 @@ namespace
 #endif
     }
 
+#if defined (__arm64__) || defined (__aarch64__)
+    //------------------------------------------------------------------------------
+    /// @class ReadDBGROperation
+    /// @brief Implements NativeProcessLinux::ReadDBGR.
+    class ReadDBGROperation : public Operation
+    {
+    public:
+        ReadDBGROperation(lldb::tid_t tid, unsigned int &count_wp, unsigned int &count_bp)
+            : m_tid(tid),
+              m_count_wp(count_wp),
+              m_count_bp(count_bp)
+            { }
+
+        void Execute(NativeProcessLinux *monitor) override;
+
+    private:
+        lldb::tid_t m_tid;
+        unsigned int &m_count_wp;
+        unsigned int &m_count_bp;
+    };
+
+    void
+    ReadDBGROperation::Execute(NativeProcessLinux *monitor)
+    {
+       int regset = NT_ARM_HW_WATCH;
+       struct iovec ioVec;
+       struct user_hwdebug_state dreg_state;
+
+       ioVec.iov_base = &dreg_state;
+       ioVec.iov_len = sizeof (dreg_state);
+
+       PTRACE(PTRACE_GETREGSET, m_tid, &regset, &ioVec, ioVec.iov_len, m_error);
+
+       m_count_wp = dreg_state.dbg_info & 0xff;
+       regset = NT_ARM_HW_BREAK;
+
+       PTRACE(PTRACE_GETREGSET, m_tid, &regset, &ioVec, ioVec.iov_len, m_error);
+       m_count_bp = dreg_state.dbg_info & 0xff;
+    }
+#endif
+
     //------------------------------------------------------------------------------
     /// @class ReadRegisterSetOperation
     /// @brief Implements NativeProcessLinux::ReadRegisterSet.
@@ -853,6 +894,57 @@ namespace
 #endif
     }
 
+#if defined (__arm64__) || defined (__aarch64__)
+    //------------------------------------------------------------------------------
+    /// @class WriteDBGROperation
+    /// @brief Implements NativeProcessLinux::WriteFPR.
+    class WriteDBGROperation : public Operation
+    {
+    public:
+        WriteDBGROperation(lldb::tid_t tid, lldb::addr_t *addr_buf,
+                           uint32_t *cntrl_buf, int type, int count)
+            : m_tid(tid),
+              m_address(addr_buf),
+              m_control(cntrl_buf),
+              m_type(type),
+              m_count(count)
+            { }
+
+        void Execute(NativeProcessLinux *monitor) override;
+
+    private:
+        lldb::tid_t m_tid;
+        lldb::addr_t * m_address;
+        uint32_t * m_control;
+        int m_type;
+        int m_count;
+    };
+
+    void
+    WriteDBGROperation::Execute(NativeProcessLinux *monitor)
+    {
+        struct iovec ioVec;
+        struct user_hwdebug_state dreg_state;
+
+        memset (&dreg_state, 0, sizeof (dreg_state));
+        ioVec.iov_len = (__builtin_offsetof (struct user_hwdebug_state, dbg_regs[m_count - 1])
+                      + sizeof (dreg_state.dbg_regs [m_count - 1]));
+
+        if (m_type == 0)
+            m_type = NT_ARM_HW_WATCH;
+        else
+            m_type = NT_ARM_HW_BREAK;
+
+        for (int i = 0; i < m_count; i++)
+        {
+            dreg_state.dbg_regs[i].addr = m_address[i];
+            dreg_state.dbg_regs[i].ctrl = m_control[i];
+        }
+
+        PTRACE(PTRACE_SETREGSET, m_tid, &m_type, &ioVec, ioVec.iov_len, m_error);
+    }
+#endif
+
     //------------------------------------------------------------------------------
     /// @class WriteRegisterSetOperation
     /// @brief Implements NativeProcessLinux::WriteRegisterSet.
@@ -2436,7 +2528,7 @@ NativeProcessLinux::MonitorSIGTRAP(const
         {
             // If a watchpoint was hit, report it
             uint32_t wp_index;
-            Error error = thread_sp->GetRegisterContext()->GetWatchpointHitIndex(wp_index);
+            Error error = thread_sp->GetRegisterContext()->GetWatchpointHitIndex(wp_index, (lldb::addr_t)info->si_addr);
             if (error.Fail() && log)
                 log->Printf("NativeProcessLinux::%s() "
                             "received error while checking for watchpoint hits, "
@@ -3841,6 +3933,26 @@ NativeProcessLinux::ReadRegisterSet(lldb
     return op.GetError();
 }
 
+#if defined (__arm64__) || defined (__aarch64__)
+
+Error
+NativeProcessLinux::ReadHardwareDebugInfo (lldb::tid_t tid, unsigned int &watch_count , unsigned int &break_count)
+{
+    ReadDBGROperation op(tid, watch_count, break_count);
+    m_monitor_up->DoOperation(&op);
+    return op.GetError();
+}
+
+Error
+NativeProcessLinux::WriteHardwareDebugRegs (lldb::tid_t tid, lldb::addr_t *addr_buf, uint32_t *cntrl_buf, int type, int count)
+{
+    WriteDBGROperation op(tid, addr_buf, cntrl_buf, type, count);
+    m_monitor_up->DoOperation(&op);
+    return op.GetError();
+}
+
+#endif
+
 Error
 NativeProcessLinux::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
 {

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Fri May 15 01:29:58 2015
@@ -151,6 +151,17 @@ namespace process_linux {
         Error
         ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
 
+#if defined (__arm64__) || defined (__aarch64__)
+        /// Reads hardware breakpoints and watchpoints capability information.
+        Error
+        ReadHardwareDebugInfo (lldb::tid_t tid, unsigned int &watch_count ,
+                               unsigned int &break_count);
+
+        /// Write hardware breakpoint/watchpoint control and address registers.
+        Error
+        WriteHardwareDebugRegs (lldb::tid_t tid, lldb::addr_t *addr_buf,
+                                uint32_t *cntrl_buf, int type, int count);
+#endif
         /// Reads the specified register set into the specified buffer.
         /// For instance, the extended floating-point register set.
         Error

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp?rev=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp Fri May 15 01:29:58 2015
@@ -12,10 +12,12 @@
 #include "lldb/lldb-private-forward.h"
 #include "lldb/Core/DataBufferHeap.h"
 #include "lldb/Core/Error.h"
+#include "lldb/Core/StreamString.h"
 #include "lldb/Core/RegisterValue.h"
 #include "lldb/Host/common/NativeProcessProtocol.h"
 #include "lldb/Host/common/NativeThreadProtocol.h"
 #include "Plugins/Process/Linux/NativeProcessLinux.h"
+#include "lldb/Core/Log.h"
 
 #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
 
@@ -149,6 +151,12 @@ NativeRegisterContextLinux_arm64::Native
 
     ::memset(&m_fpr, 0, sizeof (m_fpr));
     ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64));
+    ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs));
+
+    // 16 is just a maximum value, query hardware for actual watchpoint count
+    m_max_hwp_supported = 16;
+    m_max_hbp_supported = 16;
+    m_refresh_hwdebug_info = true;
 }
 
 uint32_t
@@ -536,3 +544,356 @@ NativeRegisterContextLinux_arm64::GetGPR
 {
     return GetRegisterInfoInterface().GetGPRSize();
 }
+
+uint32_t
+NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+        return false;
+
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+    // Check if our hardware breakpoint and watchpoint information is updated.
+    if (m_refresh_hwdebug_info)
+    {
+        process_p->ReadHardwareDebugInfo (m_thread.GetID (), m_max_hwp_supported,
+                                          m_max_hbp_supported);
+        m_refresh_hwdebug_info = false;
+    }
+
+    uint32_t control_value, bp_index;
+
+    // Check if size has a valid hardware breakpoint length.
+    if (size != 4)
+        return LLDB_INVALID_INDEX32;  // Invalid size for a AArch64 hardware breakpoint
+
+    // Check 4-byte alignment for hardware breakpoint target address.
+    if (addr & 0x03)
+        return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
+
+    // Setup control value
+    control_value = 0;
+    control_value |= ((1 << size) - 1) << 5;
+    control_value |= (2 << 1) | 1;
+
+    // Iterate over stored hardware breakpoints
+    // Find a free bp_index or update reference count if duplicate.
+    bp_index = LLDB_INVALID_INDEX32;
+    for (uint32_t i = 0; i < m_max_hbp_supported; i++)
+    {
+        if ((m_hbr_regs[i].control & 1) == 0)
+        {
+            bp_index = i;  // Mark last free slot
+        }
+        else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
+        {
+            bp_index = i;  // Mark duplicate index
+            break;  // Stop searching here
+        }
+    }
+
+     if (bp_index == LLDB_INVALID_INDEX32)
+        return LLDB_INVALID_INDEX32;
+
+    // Add new or update existing watchpoint
+    if ((m_hbr_regs[bp_index].control & 1) == 0)
+    {
+        m_hbr_regs[bp_index].address = addr;
+        m_hbr_regs[bp_index].control = control_value;
+        m_hbr_regs[bp_index].refcount = 1;
+
+        //TODO: PTRACE CALL HERE for an UPDATE
+    }
+    else
+        m_hbr_regs[bp_index].refcount++;
+
+    return bp_index;
+}
+
+bool
+NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    if (hw_idx >= m_max_hbp_supported)
+        return false;
+
+    // Update reference count if multiple references.
+    if (m_hbr_regs[hw_idx].refcount > 1)
+    {
+        m_hbr_regs[hw_idx].refcount--;
+        return true;
+    }
+    else if (m_hbr_regs[hw_idx].refcount == 1)
+    {
+        m_hbr_regs[hw_idx].control &= ~1;
+        m_hbr_regs[hw_idx].address = 0;
+        m_hbr_regs[hw_idx].refcount = 0;
+
+        //TODO: PTRACE CALL HERE for an UPDATE
+        return true;
+    }
+
+    return false;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints ()
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    return m_max_hwp_supported;
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+        return false;
+
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+    // Check if our hardware breakpoint and watchpoint information is updated.
+    if (m_refresh_hwdebug_info)
+    {
+        process_p->ReadHardwareDebugInfo (m_thread.GetID (), m_max_hwp_supported,
+                                          m_max_hbp_supported);
+        m_refresh_hwdebug_info = false;
+    }
+		
+    uint32_t control_value, wp_index;
+
+
+    if (watch_flags != 0x1 && watch_flags != 0x2 && watch_flags != 0x3)
+        return 0;//Error ("Invalid read/write bits for watchpoint");
+
+    // Check if size has a valid hardware watchpoint length.
+    if (size != 1 && size != 2 && size != 4 && size != 8)
+        return 0;//Error ("Invalid size for watchpoint");
+
+    // Check 8-byte alignment for hardware watchpoint target address.
+    // TODO: Add support for watching un-aligned addresses
+    if (addr & 0x07)
+        return 0;//Error ("LLDB for AArch64 currently supports 8-byte alignment for hardware watchpoint target address.");
+
+    // Setup control value
+    control_value = watch_flags << 3;
+    control_value |= ((1 << size) - 1) << 5;
+    control_value |= (2 << 1) | 1;
+
+    // Iterate over stored watchpoints
+    // Find a free wp_index or update reference count if duplicate.
+    wp_index = LLDB_INVALID_INDEX32;
+    for (uint32_t i = 0; i < m_max_hwp_supported; i++)
+    {
+        if ((m_hwp_regs[i].control & 1) == 0)
+        {
+            wp_index = i; // Mark last free slot
+        }
+        else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
+        {
+            wp_index = i; // Mark duplicate index
+            break; // Stop searching here
+        }
+    }
+
+     if (wp_index == LLDB_INVALID_INDEX32)
+        return LLDB_INVALID_INDEX32;
+
+    // Add new or update existing watchpoint
+    if ((m_hwp_regs[wp_index].control & 1) == 0)
+    {
+        m_hwp_regs[wp_index].address = addr;
+        m_hwp_regs[wp_index].control = control_value;
+        m_hwp_regs[wp_index].refcount = 1;
+
+        // PTRACE call to set corresponding watchpoint register.
+        process_p->WriteHardwareDebugRegs(m_thread.GetID (), &addr,
+                                          &control_value, 0, wp_index);
+    }
+    else
+        m_hwp_regs[wp_index].refcount++;
+
+    return wp_index;
+}
+
+bool
+NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+        return false;
+
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+    if (wp_index >= m_max_hwp_supported)
+        return false;
+
+    // Update reference count if multiple references.
+    if (m_hwp_regs[wp_index].refcount > 1)
+    {
+        m_hwp_regs[wp_index].refcount--;
+        return true;
+    }
+    else if (m_hwp_regs[wp_index].refcount == 1)
+    {
+        m_hwp_regs[wp_index].control &= ~1;
+        m_hwp_regs[wp_index].address = 0;
+        m_hwp_regs[wp_index].refcount = 0;
+
+        //TODO: PTRACE CALL HERE for an UPDATE
+        process_p->WriteHardwareDebugRegs(m_thread.GetID (),
+                                          &m_hwp_regs[wp_index].address,
+                                          &m_hwp_regs[wp_index].control,
+                                          0, wp_index);
+        return true;
+    }
+
+    return false;
+}
+
+Error
+NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+
+    Error ml_error;
+    ml_error.SetErrorToErrno();
+    if (!process_sp)
+        return ml_error;
+
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+    for (uint32_t i = 0; i < m_max_hwp_supported; i++)
+    {
+        if (m_hwp_regs[i].control & 0x01)
+        {
+            m_hwp_regs[i].control &= ~1;
+            m_hwp_regs[i].address = 0;
+            m_hwp_regs[i].refcount = 0;
+
+            process_p->WriteHardwareDebugRegs(m_thread.GetID (),
+                                          &m_hwp_regs[i].address,
+                                          &m_hwp_regs[i].control,
+                                          0, i);
+        }
+    }
+
+    return Error();
+}
+
+uint32_t
+NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+    switch ((m_hwp_regs[wp_index].control >> 5) & 0xff)
+    {
+        case 0x01:
+            return 1;
+        case 0x03:
+            return 2;
+        case 0x0f:
+            return 4;
+        case 0xff:
+            return 8;
+        default:
+            return 0;
+    }
+}
+bool
+NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
+        return true;
+    else
+        return false;
+}
+
+Error
+NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    uint32_t watch_size;
+    lldb::addr_t watch_addr;
+
+    for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
+    {
+        watch_size = GetWatchpointSize (wp_index);
+        watch_addr = m_hwp_regs[wp_index].address;
+
+        if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
+            && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
+        {
+            return Error();
+        }
+    }
+
+    wp_index = LLDB_INVALID_INDEX32;
+    return Error();
+}
+
+lldb::addr_t
+NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    if (wp_index >= m_max_hwp_supported)
+        return LLDB_INVALID_ADDRESS;
+
+    if (WatchpointIsEnabled(wp_index))
+        return m_hwp_regs[wp_index].address;
+    else
+        return LLDB_INVALID_ADDRESS;
+}
+
+bool
+NativeRegisterContextLinux_arm64::HardwareSingleStep (bool enable)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+
+    if (log)
+        log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
+
+    return false;
+}

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h?rev=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h Fri May 15 01:29:58 2015
@@ -44,6 +44,43 @@ namespace process_linux {
         Error
         WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
 
+        //------------------------------------------------------------------
+        // Hardware breakpoints/watchpoint mangement functions
+        //------------------------------------------------------------------
+
+        uint32_t
+        SetHardwareBreakpoint (lldb::addr_t addr, size_t size) override;
+
+        bool
+        ClearHardwareBreakpoint (uint32_t hw_idx) override;
+
+        uint32_t
+        NumSupportedHardwareWatchpoints () override;
+
+        uint32_t
+        SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) override;
+
+        bool
+        ClearHardwareWatchpoint (uint32_t hw_index) override;
+
+        Error
+        ClearAllHardwareWatchpoints () override;
+
+        Error
+        GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override;
+
+        lldb::addr_t
+        GetWatchpointAddress (uint32_t wp_index) override;
+
+        bool
+        HardwareSingleStep (bool enable) override;
+
+        uint32_t
+        GetWatchpointSize(uint32_t wp_index);
+
+        bool
+        WatchpointIsEnabled(uint32_t wp_index);
+
     private:
         struct RegInfo
         {
@@ -79,6 +116,21 @@ namespace process_linux {
         RegInfo  m_reg_info;
         FPU m_fpr; // floating-point registers including extended register sets.
 
+        // Debug register info for hardware breakpoints and watchpoints management.
+        struct DREG
+        {
+            lldb::addr_t address;  // Breakpoint/watchpoint address value.
+            uint32_t control;  // Breakpoint/watchpoint control value.
+            uint32_t refcount;  // Serves as enable/disable and refernce counter.
+        };
+
+        struct DREG m_hbr_regs[16];  // Arm native linux hardware breakpoints
+        struct DREG m_hwp_regs[16];  // Arm native linux hardware watchpoints
+
+        uint32_t m_max_hwp_supported;
+        uint32_t m_max_hbp_supported;
+        bool m_refresh_hwdebug_info;
+
         bool
         IsGPR(unsigned reg) const;
 

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp?rev=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp Fri May 15 01:29:58 2015
@@ -1069,7 +1069,7 @@ NativeRegisterContextLinux_x86_64::IsWat
 }
 
 Error
-NativeRegisterContextLinux_x86_64::GetWatchpointHitIndex(uint32_t &wp_index) {
+NativeRegisterContextLinux_x86_64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) {
     uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
     for (wp_index = 0; wp_index < num_hw_wps; ++wp_index)
     {

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h?rev=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h Fri May 15 01:29:58 2015
@@ -50,7 +50,7 @@ namespace process_linux {
         IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
 
         Error
-        GetWatchpointHitIndex(uint32_t &wp_index) override;
+        GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override;
 
         Error
         IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;

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=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Fri May 15 01:29:58 2015
@@ -548,7 +548,96 @@ ReadRegOperation::Execute(ProcessMonitor
 #endif
 }
 
-//------------------------------------------------------------------------------
+#if defined (__arm64__) || defined (__aarch64__)
+    //------------------------------------------------------------------------------
+    /// @class ReadDBGROperation
+    /// @brief Implements NativeProcessLinux::ReadDBGR.
+    class ReadDBGROperation : public Operation
+    {
+    public:
+        ReadDBGROperation(lldb::tid_t tid, unsigned int &count_wp, unsigned int &count_bp)
+            : m_tid(tid),
+              m_count_wp(count_wp),
+              m_count_bp(count_bp)
+            { }
+
+        void Execute(ProcessMonitor *monitor) override;
+
+    private:
+        lldb::tid_t m_tid;
+        unsigned int &m_count_wp;
+        unsigned int &m_count_bp;
+    };
+
+    void
+    ReadDBGROperation::Execute(ProcessMonitor *monitor)
+    {
+       int regset = NT_ARM_HW_WATCH;
+       struct iovec ioVec;
+       struct user_hwdebug_state dreg_state;
+
+       ioVec.iov_base = &dreg_state;
+       ioVec.iov_len = sizeof (dreg_state);
+
+       PTRACE(PTRACE_GETREGSET, m_tid, &regset, &ioVec, ioVec.iov_len);
+
+       m_count_wp = dreg_state.dbg_info & 0xff;
+       regset = NT_ARM_HW_BREAK;
+
+       PTRACE(PTRACE_GETREGSET, m_tid, &regset, &ioVec, ioVec.iov_len);
+       m_count_bp = dreg_state.dbg_info & 0xff;
+    }
+#endif
+
+#if defined (__arm64__) || defined (__aarch64__)
+    //------------------------------------------------------------------------------
+    /// @class WriteDBGROperation
+    /// @brief Implements NativeProcessLinux::WriteFPR.
+    class WriteDBGROperation : public Operation
+    {
+    public:
+        WriteDBGROperation(lldb::tid_t tid, lldb::addr_t *addr_buf, uint32_t *cntrl_buf, int type, int count)
+            : m_tid(tid),
+              m_addr_buf(addr_buf),
+              m_cntrl_buf(cntrl_buf),
+              m_type(type),
+              m_count(count)
+            { }
+
+        void Execute(ProcessMonitor *monitor) override;
+
+    private:
+        lldb::tid_t m_tid;
+        lldb::addr_t *m_addr_buf;
+        uint32_t *m_cntrl_buf;
+        int m_type;
+        int m_count;
+    };
+
+    void
+    WriteDBGROperation::Execute(ProcessMonitor *monitor)
+    {
+        struct iovec ioVec;
+        struct user_hwdebug_state dreg_state;
+
+        memset (&dreg_state, 0, sizeof (dreg_state));
+        ioVec.iov_len = (__builtin_offsetof (struct user_hwdebug_state, dbg_regs[m_count - 1])
+                      + sizeof (dreg_state.dbg_regs [m_count - 1]));
+
+        if (m_type == 0)
+            m_type = NT_ARM_HW_WATCH;
+        else
+            m_type = NT_ARM_HW_BREAK;
+
+        for (int i = 0; i < m_count; i++)
+        {
+            dreg_state.dbg_regs[i].addr = m_addr_buf[i];
+            dreg_state.dbg_regs[i].ctrl = m_cntrl_buf[i];
+        }
+
+        PTRACE(PTRACE_SETREGSET, m_tid, &m_type, &ioVec, ioVec.iov_len);
+    }
+#endif//------------------------------------------------------------------------------
 /// @class WriteRegOperation
 /// @brief Implements ProcessMonitor::WriteRegisterValue.
 class WriteRegOperation : public Operation
@@ -2159,6 +2248,27 @@ ProcessMonitor::ReadRegisterValue(lldb::
     return result;
 }
 
+#if defined (__arm64__) || defined (__aarch64__)
+
+bool
+ProcessMonitor::ReadHardwareDebugInfo (lldb::tid_t tid, unsigned int &watch_count , unsigned int &break_count)
+{
+    bool result = true;
+    ReadDBGROperation op(tid, watch_count, break_count);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+ProcessMonitor::WriteHardwareDebugRegs (lldb::tid_t tid, lldb::addr_t *addr_buf, uint32_t *cntrl_buf, int type, int count)
+{
+    bool result = true;
+    WriteDBGROperation op(tid, addr_buf, cntrl_buf, type, count);
+    DoOperation(&op);
+    return result;
+}
+
+#endif
 bool
 ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset,
                                    const char* reg_name, const RegisterValue &value)

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h?rev=237419&r1=237418&r2=237419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h Fri May 15 01:29:58 2015
@@ -138,6 +138,18 @@ public:
     bool
     ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
 
+#if defined (__arm64__) || defined (__aarch64__)
+    /// Reads hardware breakpoints and watchpoints capability information.
+    bool
+    ReadHardwareDebugInfo (lldb::tid_t tid, unsigned int &watch_count ,
+                           unsigned int &break_count);
+
+    /// Write hardware breakpoint/watchpoint control and address registers.
+    bool
+    WriteHardwareDebugRegs (lldb::tid_t tid, lldb::addr_t *addr_buf,
+                            uint32_t *cntrl_buf, int type, int count);
+#endif
+
     /// Reads the specified register set into the specified buffer.
     /// For instance, the extended floating-point register set.
     bool





More information about the lldb-commits mailing list