9#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
26#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr))
28#ifndef PTRACE_GETVFPREGS
29#define PTRACE_GETVFPREGS 27
30#define PTRACE_SETVFPREGS 28
32#ifndef PTRACE_GETHBPREGS
33#define PTRACE_GETHBPREGS 29
34#define PTRACE_SETHBPREGS 30
36#if !defined(PTRACE_TYPE_ARG3)
37#define PTRACE_TYPE_ARG3 void *
39#if !defined(PTRACE_TYPE_ARG4)
40#define PTRACE_TYPE_ARG4 void *
49std::unique_ptr<NativeRegisterContextLinux>
50NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
52 return std::make_unique<NativeRegisterContextLinux_arm>(target_arch,
56llvm::Expected<ArchSpec>
57NativeRegisterContextLinux::DetermineArchitecture(
lldb::tid_t tid) {
58 return HostInfo::GetArchitecture();
63NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
68 assert(target_arch.
GetMachine() == llvm::Triple::arm);
70 ::memset(&m_fpr, 0,
sizeof(m_fpr));
71 ::memset(&m_gpr_arm, 0,
sizeof(m_gpr_arm));
72 ::memset(&m_hwp_regs, 0,
sizeof(m_hwp_regs));
73 ::memset(&m_hbr_regs, 0,
sizeof(m_hbr_regs));
76 m_max_hwp_supported = 16;
77 m_max_hbp_supported = 16;
78 m_refresh_hwdebug_info =
true;
85uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount()
const {
89uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount()
const {
91 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
92 count += GetRegisterSet(set_index)->num_registers;
97NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index)
const {
98 return GetRegisterInfo().GetRegisterSet(set_index);
102NativeRegisterContextLinux_arm::ReadRegister(
const RegisterInfo *reg_info,
107 error = Status::FromErrorString(
"reg_info NULL");
118 uint32_t full_reg = reg;
127 error = ReadRegisterRaw(full_reg, reg_value);
129 if (
error.Success()) {
145 uint32_t fpr_offset = CalculateFprOffset(reg_info);
146 assert(fpr_offset <
sizeof m_fpr);
147 uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
159 reg_value.
SetBytes(src, 16, GetByteOrder());
162 assert(
false &&
"Unhandled data size.");
163 error = Status::FromErrorStringWithFormat(
"unhandled byte size: %" PRIu32,
172NativeRegisterContextLinux_arm::WriteRegister(
const RegisterInfo *reg_info,
175 return Status::FromErrorString(
"reg_info NULL");
179 return Status::FromErrorStringWithFormat(
180 "no lldb regnum for %s",
181 reg_info && reg_info->
name ? reg_info->
name :
"<unknown register>");
183 if (IsGPR(reg_index))
184 return WriteRegisterRaw(reg_index, reg_value);
186 if (IsFPR(reg_index)) {
188 uint32_t fpr_offset = CalculateFprOffset(reg_info);
189 assert(fpr_offset <
sizeof m_fpr);
190 uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
196 return Status::FromErrorString(
197 "failed - register wasn't recognized to be a GPR or an FPR, "
198 "write strategy unknown");
201Status NativeRegisterContextLinux_arm::ReadAllRegisterValues(
214 uint8_t *dst = data_sp->GetBytes();
215 ::memcpy(dst, &m_gpr_arm, GetGPRSize());
217 ::memcpy(dst, &m_fpr,
sizeof(m_fpr));
222Status NativeRegisterContextLinux_arm::WriteAllRegisterValues(
227 error = Status::FromErrorStringWithFormat(
228 "NativeRegisterContextLinux_arm::%s invalid data_sp provided",
234 error = Status::FromErrorStringWithFormat(
235 "NativeRegisterContextLinux_arm::%s data_sp contained mismatched "
236 "data size, expected %" PRIu64
", actual %" PRIu64,
241 const uint8_t *src = data_sp->GetBytes();
242 if (src ==
nullptr) {
243 error = Status::FromErrorStringWithFormat(
244 "NativeRegisterContextLinux_arm::%s "
245 "DataBuffer::GetBytes() returned a null "
250 ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
256 src += GetRegisterInfoInterface().GetGPRSize();
257 ::memcpy(&m_fpr, src,
sizeof(m_fpr));
266bool NativeRegisterContextLinux_arm::IsGPR(
unsigned reg)
const {
267 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
273bool NativeRegisterContextLinux_arm::IsFPR(
unsigned reg)
const {
274 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
280uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
281 Log *log =
GetLog(POSIXLog::Breakpoints);
283 LLDB_LOGF(log,
"NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
288 error = ReadHardwareDebugInfo();
293 LLDB_LOG(log,
"{0}", m_max_hbp_supported);
294 return m_max_hbp_supported;
298NativeRegisterContextLinux_arm::SetHardwareBreakpoint(
lldb::addr_t addr,
300 Log *log =
GetLog(POSIXLog::Breakpoints);
301 LLDB_LOG(log,
"addr: {0:x}, size: {1:x}", addr, size);
309 uint32_t control_value = 0, bp_index = 0;
315 control_value = (0x3 << 5) | 7;
319 control_value = (0xfu << 5) | 7;
328 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
329 if ((m_hbr_regs[i].control & 1) == 0) {
331 }
else if (m_hbr_regs[i].address == addr) {
340 m_hbr_regs[bp_index].real_addr = addr;
341 m_hbr_regs[bp_index].address = addr;
342 m_hbr_regs[bp_index].control = control_value;
345 error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
348 m_hbr_regs[bp_index].address = 0;
349 m_hbr_regs[bp_index].control &= ~1;
357bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
358 Log *log =
GetLog(POSIXLog::Breakpoints);
359 LLDB_LOG(log,
"hw_idx: {0}", hw_idx);
367 if (hw_idx >= m_max_hbp_supported)
372 uint32_t tempControl = m_hbr_regs[hw_idx].control;
374 m_hbr_regs[hw_idx].control &= ~1;
375 m_hbr_regs[hw_idx].address = 0;
378 error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
381 m_hbr_regs[hw_idx].control = tempControl;
382 m_hbr_regs[hw_idx].address = tempAddr;
390Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
392 Log *log =
GetLog(POSIXLog::Breakpoints);
394 LLDB_LOGF(log,
"NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
398 for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
399 break_addr = m_hbr_regs[bp_index].address;
401 if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
402 m_hbr_regs[bp_index].hit_addr = trap_addr;
411Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
412 Log *log =
GetLog(POSIXLog::Breakpoints);
414 LLDB_LOGF(log,
"NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
419 error = ReadHardwareDebugInfo();
425 uint32_t tempControl = 0;
427 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
428 if (m_hbr_regs[i].control & 0x01) {
430 tempAddr = m_hbr_regs[i].address;
431 tempControl = m_hbr_regs[i].control;
434 m_hbr_regs[i].control &= ~1;
435 m_hbr_regs[i].address = 0;
438 error = WriteHardwareDebugRegs(eDREGTypeBREAK, i);
441 m_hbr_regs[i].control = tempControl;
442 m_hbr_regs[i].address = tempAddr;
452uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
453 Log *log =
GetLog(POSIXLog::Watchpoints);
461 LLDB_LOG(log,
"{0}", m_max_hwp_supported);
462 return m_max_hwp_supported;
465uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
467 Log *log =
GetLog(POSIXLog::Watchpoints);
468 LLDB_LOG(log,
"addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
477 uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
482 switch (watch_flags) {
498 if (size == 0 || size > 4)
505 uint8_t watch_mask = (addr & 0x03) + size;
507 if (watch_mask > 0x04)
509 else if (watch_mask <= 0x02)
514 addr = addr & (~0x03);
519 addr_word_offset = addr % 4;
520 byte_mask = ((1u << size) - 1u) << addr_word_offset;
523 if (byte_mask > 0xfu)
528 control_value = byte_mask << 5;
531 control_value |= (watch_flags << 3);
541 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
542 if ((m_hwp_regs[i].control & 1) == 0) {
544 }
else if (m_hwp_regs[i].address == addr) {
553 m_hwp_regs[wp_index].real_addr = real_addr;
554 m_hwp_regs[wp_index].address = addr;
555 m_hwp_regs[wp_index].control = control_value;
558 error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
561 m_hwp_regs[wp_index].address = 0;
562 m_hwp_regs[wp_index].control &= ~1;
570bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
572 Log *log =
GetLog(POSIXLog::Watchpoints);
573 LLDB_LOG(log,
"wp_index: {0}", wp_index);
581 if (wp_index >= m_max_hwp_supported)
586 uint32_t tempControl = m_hwp_regs[wp_index].control;
589 m_hwp_regs[wp_index].control &= ~1;
590 m_hwp_regs[wp_index].address = 0;
593 error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
596 m_hwp_regs[wp_index].control = tempControl;
597 m_hwp_regs[wp_index].address = tempAddr;
605Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
613 uint32_t tempControl = 0;
615 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
616 if (m_hwp_regs[i].control & 0x01) {
618 tempAddr = m_hwp_regs[i].address;
619 tempControl = m_hwp_regs[i].control;
622 m_hwp_regs[i].control &= ~1;
623 m_hwp_regs[i].address = 0;
626 error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
629 m_hwp_regs[i].control = tempControl;
630 m_hwp_regs[i].address = tempAddr;
640uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
641 Log *log =
GetLog(POSIXLog::Watchpoints);
642 LLDB_LOG(log,
"wp_index: {0}", wp_index);
644 switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
657bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
658 Log *log =
GetLog(POSIXLog::Watchpoints);
659 LLDB_LOG(log,
"wp_index: {0}", wp_index);
661 if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
668NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
670 Log *log =
GetLog(POSIXLog::Watchpoints);
671 LLDB_LOG(log,
"wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
676 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
677 watch_size = GetWatchpointSize(wp_index);
678 watch_addr = m_hwp_regs[wp_index].address;
680 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
681 trap_addr < watch_addr + watch_size) {
682 m_hwp_regs[wp_index].hit_addr = trap_addr;
692NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
693 Log *log =
GetLog(POSIXLog::Watchpoints);
694 LLDB_LOG(log,
"wp_index: {0}", wp_index);
696 if (wp_index >= m_max_hwp_supported)
699 if (WatchpointIsEnabled(wp_index))
700 return m_hwp_regs[wp_index].real_addr;
706NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
707 Log *log =
GetLog(POSIXLog::Watchpoints);
708 LLDB_LOG(log,
"wp_index: {0}", wp_index);
710 if (wp_index >= m_max_hwp_supported)
713 if (WatchpointIsEnabled(wp_index))
714 return m_hwp_regs[wp_index].hit_addr;
719Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
722 if (!m_refresh_hwdebug_info) {
726 unsigned int cap_val;
728 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
730 sizeof(
unsigned int));
735 m_max_hwp_supported = (cap_val >> 8) & 0xff;
736 m_max_hbp_supported = cap_val & 0xff;
737 m_refresh_hwdebug_info =
false;
742Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
int hwbType,
749 if (hwbType == eDREGTypeWATCH) {
750 addr_buf = &m_hwp_regs[hwb_index].address;
751 ctrl_buf = &m_hwp_regs[hwb_index].control;
753 error = NativeProcessLinux::PtraceWrapper(
754 PTRACE_SETHBPREGS, m_thread.GetID(),
755 (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
756 sizeof(
unsigned int));
761 error = NativeProcessLinux::PtraceWrapper(
762 PTRACE_SETHBPREGS, m_thread.GetID(),
763 (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
764 sizeof(
unsigned int));
766 addr_buf = &m_hbr_regs[hwb_index].address;
767 ctrl_buf = &m_hbr_regs[hwb_index].control;
769 error = NativeProcessLinux::PtraceWrapper(
770 PTRACE_SETHBPREGS, m_thread.GetID(),
771 (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
772 sizeof(
unsigned int));
777 error = NativeProcessLinux::PtraceWrapper(
778 PTRACE_SETHBPREGS, m_thread.GetID(),
779 (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
780 sizeof(
unsigned int));
786uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
791Status NativeRegisterContextLinux_arm::DoReadRegisterValue(
792 uint32_t offset,
const char *reg_name, uint32_t size,
799 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
800 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
801 return Status::FromErrorString(
802 "Register isn't fit into the size of the GPR area");
808 value.
SetUInt32(m_gpr_arm[offset /
sizeof(uint32_t)]);
812Status NativeRegisterContextLinux_arm::DoWriteRegisterValue(
813 uint32_t offset,
const char *reg_name,
const RegisterValue &value) {
819 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
820 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
821 return Status::FromErrorString(
822 "Register isn't fit into the size of the GPR area");
832 if (offset /
sizeof(uint32_t) == gpr_pc_arm) {
835 if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) &&
837 reg_value &= (~1ull);
841 m_gpr_arm[offset /
sizeof(uint32_t)] = reg_value;
845Status NativeRegisterContextLinux_arm::ReadGPR() {
847 return NativeRegisterContextLinux::ReadGPR();
850 ioVec.iov_base = GetGPRBuffer();
851 ioVec.iov_len = GetGPRSize();
853 return ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
857Status NativeRegisterContextLinux_arm::WriteGPR() {
859 return NativeRegisterContextLinux::WriteGPR();
862 ioVec.iov_base = GetGPRBuffer();
863 ioVec.iov_len = GetGPRSize();
865 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
869Status NativeRegisterContextLinux_arm::ReadFPR() {
871 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(),
872 nullptr, GetFPRBuffer(),
876 ioVec.iov_base = GetFPRBuffer();
877 ioVec.iov_len = GetFPRSize();
879 return ReadRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
883Status NativeRegisterContextLinux_arm::WriteFPR() {
885 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(),
886 nullptr, GetFPRBuffer(),
890 ioVec.iov_base = GetFPRBuffer();
891 ioVec.iov_len = GetFPRSize();
893 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOGF(log,...)
size_t GetRegisterSetCount() const override
An architecture specification class.
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
A subclass of DataBuffer that stores a data buffer on the heap.
void SetUInt64(uint64_t uint, Type t=eTypeUInt64)
void SetUInt16(uint16_t uint)
uint64_t GetAsUInt64(uint64_t fail_value=UINT64_MAX, bool *success_ptr=nullptr) const
void SetBytes(const void *bytes, size_t length, lldb::ByteOrder byte_order)
const void * GetBytes() const
void SetType(RegisterValue::Type type)
uint32_t GetAsUInt32(uint32_t fail_value=UINT32_MAX, bool *success_ptr=nullptr) const
void SetUInt32(uint32_t uint, Type t=eTypeUInt32)
uint32_t GetByteSize() const
#define LLDB_INVALID_INDEX32
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_REGNUM
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
@ eRegisterKindLLDB
lldb's internal register numbers
Every register is described in detail including its name, alternate name (optional),...
uint32_t byte_offset
The byte offset in the register context data where this register's value is found.
uint32_t byte_size
Size in bytes of the register.
uint32_t kinds[lldb::kNumRegisterKinds]
Holds all of the various register numbers for all register kinds.
const char * name
Name of this register, can't be NULL.
uint32_t * invalidate_regs
List of registers (terminated with LLDB_INVALID_REGNUM).
Registers are grouped into register sets.