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

Tamas Berghammer tberghammer at google.com
Fri May 15 08:58:00 PDT 2015


Hi Omair,

This CL caused a build breakage for android-aarch64 (
http://lab.llvm.org:8011/builders/lldb-x86_64-ubuntu-14.04-android/builds/164).
Can you look into it why?

Thanks,
Tamas

On Fri, May 15, 2015 at 7:30 AM, Omair Javaid <omair.javaid at linaro.org>
wrote:

> 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
>
>
> _______________________________________________
> lldb-commits mailing list
> lldb-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20150515/0eb42a36/attachment.html>


More information about the lldb-commits mailing list