9#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
26#if defined(__arm64__) || defined(__aarch64__)
31#include <asm/ptrace.h>
33#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr) + sizeof(m_tls))
35#ifndef PTRACE_GETVFPREGS
36#define PTRACE_GETVFPREGS 27
37#define PTRACE_SETVFPREGS 28
39#if defined(__arm__) && !defined(PTRACE_GETHBPREGS)
40#define PTRACE_GETHBPREGS 29
41#define PTRACE_SETHBPREGS 30
43#if !defined(PTRACE_TYPE_ARG3)
44#define PTRACE_TYPE_ARG3 void *
46#if !defined(PTRACE_TYPE_ARG4)
47#define PTRACE_TYPE_ARG4 void *
56std::unique_ptr<NativeRegisterContextLinux>
59 return std::make_unique<NativeRegisterContextLinux_arm>(target_arch,
63llvm::Expected<ArchSpec>
65 return HostInfo::GetArchitecture();
70NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
76 assert(target_arch.GetMachine() == llvm::Triple::arm);
78 ::memset(&m_fpr, 0,
sizeof(m_fpr));
79 ::memset(&m_tls, 0,
sizeof(m_tls));
80 ::memset(&m_gpr_arm, 0,
sizeof(m_gpr_arm));
81 ::memset(&m_hwp_regs, 0,
sizeof(m_hwp_regs));
82 ::memset(&m_hbp_regs, 0,
sizeof(m_hbp_regs));
85 m_max_hwp_supported = 16;
86 m_max_hbp_supported = 16;
87 m_refresh_hwdebug_info =
true;
94uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount()
const {
98uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount()
const {
100 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
101 count += GetRegisterSet(set_index)->num_registers;
106NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index)
const {
107 return GetRegisterInfo().GetRegisterSet(set_index);
111NativeRegisterContextLinux_arm::ReadRegister(
const RegisterInfo *reg_info,
126 }
else if (IsTLS(reg)) {
132 uint32_t full_reg = reg;
141 error = ReadRegisterRaw(full_reg, reg_value);
143 if (
error.Success()) {
159 uint32_t fpr_offset = CalculateFprOffset(reg_info);
160 assert(fpr_offset <
sizeof m_fpr);
161 uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
173 reg_value.
SetBytes(src, 16, GetByteOrder());
176 assert(
false &&
"Unhandled data size.");
186NativeRegisterContextLinux_arm::WriteRegister(
const RegisterInfo *reg_info,
194 "no lldb regnum for %s",
195 reg_info && reg_info->
name ? reg_info->
name :
"<unknown register>");
197 if (IsGPR(reg_index))
198 return WriteRegisterRaw(reg_index, reg_value);
200 if (IsFPR(reg_index)) {
202 uint32_t fpr_offset = CalculateFprOffset(reg_info);
203 assert(fpr_offset <
sizeof m_fpr);
204 uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
210 if (IsTLS(reg_index))
212 "writing to a thread pointer register is not implemented");
215 "failed - register wasn't recognized to be a GPR or an FPR, "
216 "write strategy unknown");
219Status NativeRegisterContextLinux_arm::ReadAllRegisterValues(
236 uint8_t *dst = data_sp->GetBytes();
237 ::memcpy(dst, &m_gpr_arm, GetGPRSize());
239 ::memcpy(dst, &m_fpr,
sizeof(m_fpr));
240 dst +=
sizeof(m_fpr);
241 ::memcpy(dst, &m_tls,
sizeof(m_tls));
246Status NativeRegisterContextLinux_arm::WriteAllRegisterValues(
252 "NativeRegisterContextLinux_arm::%s invalid data_sp provided",
259 "NativeRegisterContextLinux_arm::%s data_sp contained mismatched "
260 "data size, expected %" PRIu64
", actual %" PRIu64,
265 const uint8_t *src = data_sp->GetBytes();
266 if (src ==
nullptr) {
268 "NativeRegisterContextLinux_arm::%s "
269 "DataBuffer::GetBytes() returned a null "
274 ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
280 src += GetRegisterInfoInterface().GetGPRSize();
281 ::memcpy(&m_fpr, src,
sizeof(m_fpr));
292bool NativeRegisterContextLinux_arm::IsGPR(
unsigned reg)
const {
293 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
299bool NativeRegisterContextLinux_arm::IsFPR(
unsigned reg)
const {
300 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
306bool NativeRegisterContextLinux_arm::IsTLS(
unsigned reg)
const {
307 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
311llvm::Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
312 if (!m_refresh_hwdebug_info)
313 return llvm::Error::success();
316 unsigned int cap_val;
318 PTRACE_GETHBPREGS, m_thread.GetID(),
nullptr, &cap_val,
319 sizeof(
unsigned int));
322 return error.ToError();
324 m_max_hwp_supported = (cap_val >> 8) & 0xff;
325 m_max_hbp_supported = cap_val & 0xff;
326 m_refresh_hwdebug_info =
false;
328 return error.ToError();
337NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(DREGType hwbType) {
339 uint32_t max_index = m_max_hbp_supported;
340 if (hwbType == eDREGTypeWATCH)
341 max_index = m_max_hwp_supported;
343 for (uint32_t idx = 0; idx < max_index; ++idx)
344 if (
auto error = WriteHardwareDebugReg(hwbType, idx))
347 return llvm::Error::success();
349 uint32_t max_supported =
351 ? m_max_hwp_supported
352 : m_max_hbp_supported;
364NativeRegisterContextLinux_arm::WriteHardwareDebugReg(DREGType hwbType,
369 int addr_idx = (hwb_index << 1) + 1;
370 int ctrl_idx = addr_idx + 1;
374 addr_buf = &m_hwp_regs[hwb_index].address;
376 ctrl_buf = &m_hwp_regs[hwb_index].control;
378 addr_buf = &m_hbp_regs[hwb_index].address;
379 ctrl_buf = &m_hbp_regs[hwb_index].control;
383 PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)addr_idx,
384 addr_buf,
sizeof(
unsigned int));
387 return error.ToError();
390 PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)ctrl_idx,
391 ctrl_buf,
sizeof(
unsigned int));
393 return error.ToError();
397uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
402Status NativeRegisterContextLinux_arm::DoReadRegisterValue(
403 uint32_t offset,
const char *reg_name, uint32_t size,
410 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
411 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
413 "Register isn't fit into the size of the GPR area");
419 value.
SetUInt32(m_gpr_arm[offset /
sizeof(uint32_t)]);
423Status NativeRegisterContextLinux_arm::DoWriteRegisterValue(
424 uint32_t offset,
const char *reg_name,
const RegisterValue &value) {
430 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
431 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
433 "Register isn't fit into the size of the GPR area");
443 if (offset /
sizeof(uint32_t) ==
gpr_pc_arm) {
448 reg_value &= (~1ull);
452 m_gpr_arm[offset /
sizeof(uint32_t)] = reg_value;
456Status NativeRegisterContextLinux_arm::ReadGPR() {
461 ioVec.iov_base = GetGPRBuffer();
462 ioVec.iov_len = GetGPRSize();
464 return ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
468Status NativeRegisterContextLinux_arm::WriteGPR() {
473 ioVec.iov_base = GetGPRBuffer();
474 ioVec.iov_len = GetGPRSize();
476 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
480Status NativeRegisterContextLinux_arm::ReadFPR() {
483 nullptr, GetFPRBuffer(),
487 ioVec.iov_base = GetFPRBuffer();
488 ioVec.iov_len = GetFPRSize();
490 return ReadRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
494Status NativeRegisterContextLinux_arm::WriteFPR() {
497 nullptr, GetFPRBuffer(),
501 ioVec.iov_base = GetFPRBuffer();
502 ioVec.iov_len = GetFPRSize();
504 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
508Status NativeRegisterContextLinux_arm::ReadTLS() {
511 m_thread.GetID(),
nullptr,
512 GetTLSBuffer(), GetTLSSize());
517 ioVec.iov_base = GetTLSBuffer();
518 ioVec.iov_len = GetTLSSize();
520 return ReadRegisterSet(&ioVec, GetTLSSize(), NT_ARM_TLS);
static llvm::raw_ostream & error(Stream &strm)
#define PTRACE_GET_THREAD_AREA
size_t GetRegisterSetCount() const override
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
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
static Status FromErrorString(const char *str)
static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr=nullptr, void *data=nullptr, size_t data_size=0, long *result=nullptr)
}
static std::unique_ptr< NativeRegisterContextLinux > CreateHostNativeRegisterContextLinux(const ArchSpec &target_arch, NativeThreadLinux &native_thread)
virtual Status WriteGPR()
static llvm::Expected< ArchSpec > DetermineArchitecture(lldb::tid_t tid)
#define LLDB_INVALID_REGNUM
Status WriteHardwareDebugRegs(int hwbType, ::pid_t tid, uint32_t max_supported, const std::array< NativeRegisterContextDBReg::DREG, 16 > ®s)
Status ReadHardwareDebugInfo(::pid_t tid, uint32_t &max_hwp_supported, uint32_t &max_hbp_supported)
A class that represents a running process on the host machine.
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.