Index: include/lldb/Host/common/NativeRegisterContext.h =================================================================== --- include/lldb/Host/common/NativeRegisterContext.h +++ include/lldb/Host/common/NativeRegisterContext.h @@ -103,7 +103,7 @@ 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); Index: source/Host/common/NativeRegisterContext.cpp =================================================================== --- source/Host/common/NativeRegisterContext.cpp +++ source/Host/common/NativeRegisterContext.cpp @@ -309,7 +309,7 @@ } 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"); Index: source/Plugins/Process/Linux/NativeProcessLinux.h =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.h +++ source/Plugins/Process/Linux/NativeProcessLinux.h @@ -150,6 +150,17 @@ 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 Index: source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -812,7 +812,48 @@ #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, ®set, &ioVec, ioVec.iov_len, m_error); + + m_count_wp = dreg_state.dbg_info & 0xff; + regset = NT_ARM_HW_BREAK; + + PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len, m_error); + m_count_bp = dreg_state.dbg_info & 0xff; + } +#endif + + //------------------------------------------------------------------------------ /// @class ReadRegisterSetOperation /// @brief Implements NativeProcessLinux::ReadRegisterSet. class ReadRegisterSetOperation : public Operation @@ -903,7 +944,58 @@ #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. class WriteRegisterSetOperation : public Operation @@ -2486,7 +2578,7 @@ { // 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, " @@ -3904,7 +3996,27 @@ 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) { WriteGPROperation op(tid, buf, buf_size); Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -44,6 +44,43 @@ 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 @@ 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; Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -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 @@ ::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 @@ { 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 (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 (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 (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 (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; +} Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h @@ -50,7 +50,7 @@ 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; Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -1069,7 +1069,7 @@ } 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) { Index: source/Plugins/Process/Linux/ProcessMonitor.h =================================================================== --- source/Plugins/Process/Linux/ProcessMonitor.h +++ source/Plugins/Process/Linux/ProcessMonitor.h @@ -138,6 +138,18 @@ 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 Index: source/Plugins/Process/Linux/ProcessMonitor.cpp =================================================================== --- source/Plugins/Process/Linux/ProcessMonitor.cpp +++ source/Plugins/Process/Linux/ProcessMonitor.cpp @@ -573,7 +573,96 @@ #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, ®set, &ioVec, ioVec.iov_len); + + m_count_wp = dreg_state.dbg_info & 0xff; + regset = NT_ARM_HW_BREAK; + + PTRACE(PTRACE_GETREGSET, m_tid, ®set, &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 @@ -2184,7 +2273,28 @@ 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) {