Index: include/lldb/Host/linux/Ptrace.h =================================================================== --- include/lldb/Host/linux/Ptrace.h +++ include/lldb/Host/linux/Ptrace.h @@ -63,4 +63,17 @@ #define LLDB_PTRACE_NT_ARM_TLS 0x401 // ARM TLS register +#if defined (__arm__) || defined (__thumb__) +#ifndef PTRACE_GETHBPREGS + #define PTRACE_GETHBPREGS 29 + #define PTRACE_SETHBPREGS 30 +#endif +#if !defined(PTRACE_TYPE_ARG3) + #define PTRACE_TYPE_ARG3 void * +#endif +#if !defined(PTRACE_TYPE_ARG4) + #define PTRACE_TYPE_ARG4 void * +#endif +#endif + #endif // liblldb_Host_linux_Ptrace_h_ Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h @@ -58,6 +58,43 @@ size_t GetFPRSize() override { return sizeof(m_fpr); } + //------------------------------------------------------------------ + // 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 { @@ -93,12 +130,33 @@ uint32_t m_gpr_arm[k_num_gpr_registers_arm]; RegInfo m_reg_info; FPU m_fpr; + + // 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; // Used for enable/disable and refernce count + }; + + 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; bool IsFPR(unsigned reg) const; + + Error + ReadHardwareDebugInfo(unsigned int &watch_count , unsigned int &break_count); + + Error + WriteHardwareDebugRegs(lldb::addr_t *addr_buf, uint32_t *cntrl_buf, int type, int count); }; } // namespace process_linux Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -13,10 +13,17 @@ #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" +#include "lldb/Core/StreamString.h" + +#include "lldb/Host/linux/Ptrace.h" +#include "Plugins/Process/Linux/NativeProcessLinux.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm.h" + + #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr)) using namespace lldb; @@ -105,6 +112,90 @@ { "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm } }; +namespace +{ + +class ReadDBGROperation : public NativeProcessLinux::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; +}; + +class WriteDBGROperation : public NativeProcessLinux::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(NativeProcessLinux *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; +}; + +} // end of anonymous namespace + +void +ReadDBGROperation::Execute(NativeProcessLinux *monitor) +{ + + + unsigned int cap_val; + + NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_tid, nullptr, &cap_val, sizeof(unsigned int), m_error); + + m_count_wp = (cap_val >> 8) & 0xff; + m_count_bp = cap_val & 0xff; + +} + +void +WriteDBGROperation::Execute(NativeProcessLinux *monitor) +{ + if (m_type) + { + NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, m_tid, + (PTRACE_TYPE_ARG3) ((m_count << 1) + 1), + m_addr_buf, sizeof(unsigned int), m_error); + + NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, m_tid, + (PTRACE_TYPE_ARG3) ((m_count << 1) + 2), + m_cntrl_buf, sizeof(unsigned int), m_error); + + } + else + { + NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, m_tid, + (PTRACE_TYPE_ARG3) -((m_count << 1) + 1), + m_addr_buf, sizeof(unsigned int), m_error); + + NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, m_tid, + (PTRACE_TYPE_ARG3) -((m_count << 1) + 2), + m_cntrl_buf, sizeof(unsigned int), m_error); + } +} + NativeRegisterContextLinux* NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch, NativeThreadProtocol &native_thread, @@ -138,6 +229,13 @@ ::memset(&m_fpr, 0, sizeof (m_fpr)); ::memset(&m_gpr_arm, 0, sizeof (m_gpr_arm)); + ::memset(&m_hbr_regs, 0, sizeof (m_hbr_regs)); + ::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 @@ -360,4 +458,373 @@ return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); } +uint32_t +NativeRegisterContextLinux_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); + + // Check if our hardware breakpoint and watchpoint information is updated. + if (m_refresh_hwdebug_info) + { + ReadHardwareDebugInfo (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. + // Thumb instructions are 2-bytes but we have no way here to determine + // if target address is a thumb or arm instruction. + // TODO: Add support for setting thumb mode hardware breakpoints + if (size != 4 && size != 2) + return LLDB_INVALID_INDEX32; + + // Setup control value + // Make the byte_mask into a valid Byte Address Select mask + control_value = 0xfu << 5; + + // Enable this breakpoint and make it stop in privileged or user mode; + control_value |= 7; + + // Make sure bits 1:0 are clear in our address + // This should be different once we support thumb here. + addr &= ~((lldb::addr_t)3); + + // 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_arm::ClearHardwareBreakpoint (uint32_t hw_idx) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%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_arm::NumSupportedHardwareWatchpoints () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); + + return m_max_hwp_supported; +} + +uint32_t +NativeRegisterContextLinux_arm::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_arm::%s()", __FUNCTION__); + + // Check if our hardware breakpoint and watchpoint information is updated. + if (m_refresh_hwdebug_info) + { + ReadHardwareDebugInfo (m_max_hwp_supported, m_max_hbp_supported); + m_refresh_hwdebug_info = false; + } + + uint32_t control_value, wp_index, addr_word_offset, byte_mask; + // Can't watch zero bytes + // Can't watch more than 4 bytes per WVR/WCR pair + lldb_private::StreamString output_stream; + output_stream.Printf("Watchpoint created: "); + + if (size == 0 || size > 4) + return LLDB_INVALID_INDEX32; + + // We can only watch up to four bytes that follow a 4 byte aligned address + // per watchpoint register pair, so make sure we can properly encode this. + addr_word_offset = addr % 4; + byte_mask = ((1u << size) - 1u) << addr_word_offset; + + // Check if we need multiple watchpoint register + if (byte_mask > 0xfu) + return LLDB_INVALID_INDEX32; + + // Setup control value + // Make the byte_mask into a valid Byte Address Select mask + control_value = byte_mask << 5; + + //Turn on appropriate watchpoint flags read or write + control_value |= (watch_flags << 3); + + // Enable this watchpoint and make it stop in privileged or user mode; + control_value |= 7; + + // Make sure bits 1:0 are clear in our address + addr &= ~((lldb::addr_t)3); + + // 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. + WriteHardwareDebugRegs(&addr, &control_value, 0, wp_index); + } + else + m_hwp_regs[wp_index].refcount++; + + return wp_index; +} + +bool +NativeRegisterContextLinux_arm::ClearHardwareWatchpoint (uint32_t wp_index) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); + + 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 + WriteHardwareDebugRegs(&m_hwp_regs[wp_index].address, + &m_hwp_regs[wp_index].control, + 0, wp_index); + + return true; + } + + return false; +} + +Error +NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); + + 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; + + WriteHardwareDebugRegs(&m_hwp_regs[i].address, + &m_hwp_regs[i].control, + 0, i); + } + } + + return Error(); +} + +uint32_t +NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); + + switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) + { + case 0x01: + return 1; + case 0x03: + return 2; + case 0x07: + return 3; + case 0x0f: + return 4; + default: + return 0; + } +} +bool +NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); + + if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) + return true; + else + return false; +} + +Error +NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%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_arm::GetWatchpointAddress (uint32_t wp_index) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%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_arm::HardwareSingleStep (bool enable) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); + + if (log) + log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); + + return false; +} + +Error +NativeRegisterContextLinux_arm::ReadHardwareDebugInfo(unsigned int &watch_count, + unsigned int &break_count) +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + NativeProcessLinux *const process_p = reinterpret_cast(process_sp.get()); + + ReadDBGROperation op(m_thread.GetID(), watch_count, break_count); + return process_p->DoOperation(&op); +} + +Error +NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(lldb::addr_t *addr_buf, + uint32_t *cntrl_buf, + int type, + int count) +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + NativeProcessLinux *const process_p = reinterpret_cast(process_sp.get()); + + WriteDBGROperation op(m_thread.GetID(), addr_buf, cntrl_buf, type, count); + return process_p->DoOperation(&op); +} + #endif // defined(__arm__) Index: source/Plugins/Process/Linux/ProcessMonitor.h =================================================================== --- source/Plugins/Process/Linux/ProcessMonitor.h +++ source/Plugins/Process/Linux/ProcessMonitor.h @@ -139,7 +139,6 @@ 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 , @@ -149,7 +148,6 @@ 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. Index: source/Plugins/Process/Linux/ProcessMonitor.cpp =================================================================== --- source/Plugins/Process/Linux/ProcessMonitor.cpp +++ source/Plugins/Process/Linux/ProcessMonitor.cpp @@ -546,96 +546,132 @@ #endif } +//------------------------------------------------------------------------------ +/// @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) +{ #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; - }; + int regset = NT_ARM_HW_WATCH; + struct iovec ioVec; + struct user_hwdebug_state dreg_state; - 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); - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof (dreg_state); + PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len); - PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len); + m_count_wp = dreg_state.dbg_info & 0xff; + regset = NT_ARM_HW_BREAK; - 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; + +#elif defined (__arm__) || defined (__thumb__) + + unsigned int cap_val; + + PTRACE(PTRACE_GETHBPREGS, m_tid, nullptr, &cap_val, sizeof(unsigned int)); + + m_count_wp = (cap_val >> 8) & 0xff; + m_count_bp = cap_val & 0xff; - PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len); - m_count_bp = dreg_state.dbg_info & 0xff; - } #endif +} +//------------------------------------------------------------------------------ +/// @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) +{ #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; - }; + struct iovec ioVec; + struct user_hwdebug_state dreg_state; - void - WriteDBGROperation::Execute(ProcessMonitor *monitor) + memset (&dreg_state, 0, sizeof (dreg_state)); + ioVec.iov_base = &dreg_state; + ioVec.iov_len = sizeof(dreg_state); + + 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++) { - struct iovec ioVec; - struct user_hwdebug_state dreg_state; + dreg_state.dbg_regs[i].addr = m_addr_buf[i]; + dreg_state.dbg_regs[i].ctrl = m_cntrl_buf[i]; + } - memset (&dreg_state, 0, sizeof (dreg_state)); - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof(dreg_state); + PTRACE(PTRACE_SETREGSET, m_tid, &m_type, &ioVec, ioVec.iov_len); - if (m_type == 0) - m_type = NT_ARM_HW_WATCH; - else - m_type = NT_ARM_HW_BREAK; +#elif defined (__arm__) || defined (__thumb__) - 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]; - } + if (m_type) + { + PTRACE(PTRACE_SETHBPREGS, m_tid, + (PTRACE_TYPE_ARG3) ((m_count << 1) + 1), + m_addr_buf, sizeof(unsigned int)); + + PTRACE(PTRACE_SETHBPREGS, m_tid, + (PTRACE_TYPE_ARG3) ((m_count << 1) + 2), + m_cntrl_buf, sizeof(unsigned int)); + + } + else + { + PTRACE(PTRACE_SETHBPREGS, m_tid, + (PTRACE_TYPE_ARG3) -((m_count << 1) + 1), + m_addr_buf, sizeof(unsigned int)); - PTRACE(PTRACE_SETREGSET, m_tid, &m_type, &ioVec, ioVec.iov_len); + PTRACE(PTRACE_SETHBPREGS, m_tid, + (PTRACE_TYPE_ARG3) -((m_count << 1) + 2), + m_cntrl_buf, sizeof(unsigned int)); } -#endif//------------------------------------------------------------------------------ +#endif +} + +//------------------------------------------------------------------------------ /// @class WriteRegOperation /// @brief Implements ProcessMonitor::WriteRegisterValue. class WriteRegOperation : public Operation @@ -2248,8 +2284,6 @@ return result; } -#if defined (__arm64__) || defined (__aarch64__) - bool ProcessMonitor::ReadHardwareDebugInfo (lldb::tid_t tid, unsigned int &watch_count , unsigned int &break_count) { @@ -2268,7 +2302,6 @@ return result; } -#endif bool ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char* reg_name, const RegisterValue &value)