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.SetErrorString(
"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.SetErrorStringWithFormat(
"unhandled byte size: %" PRIu32,
172NativeRegisterContextLinux_arm::WriteRegister(
const RegisterInfo *reg_info,
175 return Status(
"reg_info NULL");
179 return Status(
"no lldb regnum for %s", reg_info && reg_info->
name
181 :
"<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(
"failed - register wasn't recognized to be a GPR or an FPR, "
197 "write strategy unknown");
200Status NativeRegisterContextLinux_arm::ReadAllRegisterValues(
213 uint8_t *dst = data_sp->GetBytes();
214 ::memcpy(dst, &m_gpr_arm, GetGPRSize());
216 ::memcpy(dst, &m_fpr,
sizeof(m_fpr));
221Status NativeRegisterContextLinux_arm::WriteAllRegisterValues(
226 error.SetErrorStringWithFormat(
227 "NativeRegisterContextLinux_arm::%s invalid data_sp provided",
233 error.SetErrorStringWithFormat(
234 "NativeRegisterContextLinux_arm::%s data_sp contained mismatched "
235 "data size, expected %" PRIu64
", actual %" PRIu64,
240 const uint8_t *src = data_sp->GetBytes();
241 if (src ==
nullptr) {
242 error.SetErrorStringWithFormat(
"NativeRegisterContextLinux_arm::%s "
243 "DataBuffer::GetBytes() returned a null "
248 ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
254 src += GetRegisterInfoInterface().GetGPRSize();
255 ::memcpy(&m_fpr, src,
sizeof(m_fpr));
264bool NativeRegisterContextLinux_arm::IsGPR(
unsigned reg)
const {
265 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
271bool NativeRegisterContextLinux_arm::IsFPR(
unsigned reg)
const {
272 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
278uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
279 Log *log =
GetLog(POSIXLog::Breakpoints);
281 LLDB_LOGF(log,
"NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
286 error = ReadHardwareDebugInfo();
291 LLDB_LOG(log,
"{0}", m_max_hbp_supported);
292 return m_max_hbp_supported;
296NativeRegisterContextLinux_arm::SetHardwareBreakpoint(
lldb::addr_t addr,
298 Log *log =
GetLog(POSIXLog::Breakpoints);
299 LLDB_LOG(log,
"addr: {0:x}, size: {1:x}", addr, size);
307 uint32_t control_value = 0, bp_index = 0;
313 control_value = (0x3 << 5) | 7;
317 control_value = (0xfu << 5) | 7;
326 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
327 if ((m_hbr_regs[i].control & 1) == 0) {
329 }
else if (m_hbr_regs[i].address == addr) {
338 m_hbr_regs[bp_index].real_addr = addr;
339 m_hbr_regs[bp_index].address = addr;
340 m_hbr_regs[bp_index].control = control_value;
343 error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
346 m_hbr_regs[bp_index].address = 0;
347 m_hbr_regs[bp_index].control &= ~1;
355bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
356 Log *log =
GetLog(POSIXLog::Breakpoints);
357 LLDB_LOG(log,
"hw_idx: {0}", hw_idx);
365 if (hw_idx >= m_max_hbp_supported)
370 uint32_t tempControl = m_hbr_regs[hw_idx].control;
372 m_hbr_regs[hw_idx].control &= ~1;
373 m_hbr_regs[hw_idx].address = 0;
376 error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
379 m_hbr_regs[hw_idx].control = tempControl;
380 m_hbr_regs[hw_idx].address = tempAddr;
388Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
390 Log *log =
GetLog(POSIXLog::Breakpoints);
392 LLDB_LOGF(log,
"NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
396 for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
397 break_addr = m_hbr_regs[bp_index].address;
399 if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
400 m_hbr_regs[bp_index].hit_addr = trap_addr;
409Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
410 Log *log =
GetLog(POSIXLog::Breakpoints);
412 LLDB_LOGF(log,
"NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
417 error = ReadHardwareDebugInfo();
423 uint32_t tempControl = 0;
425 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
426 if (m_hbr_regs[i].control & 0x01) {
428 tempAddr = m_hbr_regs[i].address;
429 tempControl = m_hbr_regs[i].control;
432 m_hbr_regs[i].control &= ~1;
433 m_hbr_regs[i].address = 0;
436 error = WriteHardwareDebugRegs(eDREGTypeBREAK, i);
439 m_hbr_regs[i].control = tempControl;
440 m_hbr_regs[i].address = tempAddr;
450uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
451 Log *log =
GetLog(POSIXLog::Watchpoints);
459 LLDB_LOG(log,
"{0}", m_max_hwp_supported);
460 return m_max_hwp_supported;
463uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
465 Log *log =
GetLog(POSIXLog::Watchpoints);
466 LLDB_LOG(log,
"addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
475 uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
480 switch (watch_flags) {
496 if (size == 0 || size > 4)
503 uint8_t watch_mask = (addr & 0x03) + size;
505 if (watch_mask > 0x04)
507 else if (watch_mask <= 0x02)
512 addr = addr & (~0x03);
517 addr_word_offset = addr % 4;
518 byte_mask = ((1u << size) - 1u) << addr_word_offset;
521 if (byte_mask > 0xfu)
526 control_value = byte_mask << 5;
529 control_value |= (watch_flags << 3);
539 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
540 if ((m_hwp_regs[i].control & 1) == 0) {
542 }
else if (m_hwp_regs[i].address == addr) {
551 m_hwp_regs[wp_index].real_addr = real_addr;
552 m_hwp_regs[wp_index].address = addr;
553 m_hwp_regs[wp_index].control = control_value;
556 error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
559 m_hwp_regs[wp_index].address = 0;
560 m_hwp_regs[wp_index].control &= ~1;
568bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
570 Log *log =
GetLog(POSIXLog::Watchpoints);
571 LLDB_LOG(log,
"wp_index: {0}", wp_index);
579 if (wp_index >= m_max_hwp_supported)
584 uint32_t tempControl = m_hwp_regs[wp_index].control;
587 m_hwp_regs[wp_index].control &= ~1;
588 m_hwp_regs[wp_index].address = 0;
591 error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
594 m_hwp_regs[wp_index].control = tempControl;
595 m_hwp_regs[wp_index].address = tempAddr;
603Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
611 uint32_t tempControl = 0;
613 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
614 if (m_hwp_regs[i].control & 0x01) {
616 tempAddr = m_hwp_regs[i].address;
617 tempControl = m_hwp_regs[i].control;
620 m_hwp_regs[i].control &= ~1;
621 m_hwp_regs[i].address = 0;
624 error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
627 m_hwp_regs[i].control = tempControl;
628 m_hwp_regs[i].address = tempAddr;
638uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
639 Log *log =
GetLog(POSIXLog::Watchpoints);
640 LLDB_LOG(log,
"wp_index: {0}", wp_index);
642 switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
655bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
656 Log *log =
GetLog(POSIXLog::Watchpoints);
657 LLDB_LOG(log,
"wp_index: {0}", wp_index);
659 if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
666NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
668 Log *log =
GetLog(POSIXLog::Watchpoints);
669 LLDB_LOG(log,
"wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
674 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
675 watch_size = GetWatchpointSize(wp_index);
676 watch_addr = m_hwp_regs[wp_index].address;
678 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
679 trap_addr < watch_addr + watch_size) {
680 m_hwp_regs[wp_index].hit_addr = trap_addr;
690NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
691 Log *log =
GetLog(POSIXLog::Watchpoints);
692 LLDB_LOG(log,
"wp_index: {0}", wp_index);
694 if (wp_index >= m_max_hwp_supported)
697 if (WatchpointIsEnabled(wp_index))
698 return m_hwp_regs[wp_index].real_addr;
704NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
705 Log *log =
GetLog(POSIXLog::Watchpoints);
706 LLDB_LOG(log,
"wp_index: {0}", wp_index);
708 if (wp_index >= m_max_hwp_supported)
711 if (WatchpointIsEnabled(wp_index))
712 return m_hwp_regs[wp_index].hit_addr;
717Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
720 if (!m_refresh_hwdebug_info) {
724 unsigned int cap_val;
726 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
728 sizeof(
unsigned int));
733 m_max_hwp_supported = (cap_val >> 8) & 0xff;
734 m_max_hbp_supported = cap_val & 0xff;
735 m_refresh_hwdebug_info =
false;
740Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
int hwbType,
747 if (hwbType == eDREGTypeWATCH) {
748 addr_buf = &m_hwp_regs[hwb_index].address;
749 ctrl_buf = &m_hwp_regs[hwb_index].control;
751 error = NativeProcessLinux::PtraceWrapper(
752 PTRACE_SETHBPREGS, m_thread.GetID(),
753 (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
754 sizeof(
unsigned int));
759 error = NativeProcessLinux::PtraceWrapper(
760 PTRACE_SETHBPREGS, m_thread.GetID(),
761 (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
762 sizeof(
unsigned int));
764 addr_buf = &m_hbr_regs[hwb_index].address;
765 ctrl_buf = &m_hbr_regs[hwb_index].control;
767 error = NativeProcessLinux::PtraceWrapper(
768 PTRACE_SETHBPREGS, m_thread.GetID(),
769 (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
770 sizeof(
unsigned int));
775 error = NativeProcessLinux::PtraceWrapper(
776 PTRACE_SETHBPREGS, m_thread.GetID(),
777 (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
778 sizeof(
unsigned int));
784uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
789Status NativeRegisterContextLinux_arm::DoReadRegisterValue(
790 uint32_t offset,
const char *reg_name, uint32_t size,
797 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
798 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
799 return Status(
"Register isn't fit into the size of the GPR area");
805 value.
SetUInt32(m_gpr_arm[offset /
sizeof(uint32_t)]);
809Status NativeRegisterContextLinux_arm::DoWriteRegisterValue(
810 uint32_t offset,
const char *reg_name,
const RegisterValue &value) {
816 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
817 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
818 return Status(
"Register isn't fit into the size of the GPR area");
828 if (offset /
sizeof(uint32_t) == gpr_pc_arm) {
831 if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) &&
833 reg_value &= (~1ull);
837 m_gpr_arm[offset /
sizeof(uint32_t)] = reg_value;
841Status NativeRegisterContextLinux_arm::ReadGPR() {
843 return NativeRegisterContextLinux::ReadGPR();
846 ioVec.iov_base = GetGPRBuffer();
847 ioVec.iov_len = GetGPRSize();
849 return ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
853Status NativeRegisterContextLinux_arm::WriteGPR() {
855 return NativeRegisterContextLinux::WriteGPR();
858 ioVec.iov_base = GetGPRBuffer();
859 ioVec.iov_len = GetGPRSize();
861 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
865Status NativeRegisterContextLinux_arm::ReadFPR() {
867 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(),
868 nullptr, GetFPRBuffer(),
872 ioVec.iov_base = GetFPRBuffer();
873 ioVec.iov_len = GetFPRSize();
875 return ReadRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
879Status NativeRegisterContextLinux_arm::WriteFPR() {
881 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(),
882 nullptr, GetFPRBuffer(),
886 ioVec.iov_base = GetFPRBuffer();
887 ioVec.iov_len = GetFPRSize();
889 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.