9#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
23#if defined(__arm64__) || defined(__aarch64__)
30#include <sys/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 *
50#ifndef PTRACE_GET_THREAD_AREA
51#define PTRACE_GET_THREAD_AREA 22
60std::unique_ptr<NativeRegisterContextLinux>
63 return std::make_unique<NativeRegisterContextLinux_arm>(target_arch,
67llvm::Expected<ArchSpec>
69 return HostInfo::GetArchitecture();
74NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
80 assert(target_arch.GetMachine() == llvm::Triple::arm);
82 ::memset(&m_fpr, 0,
sizeof(m_fpr));
83 ::memset(&m_tls, 0,
sizeof(m_tls));
84 ::memset(&m_gpr_arm, 0,
sizeof(m_gpr_arm));
87 m_max_hwp_supported = 16;
88 m_max_hbp_supported = 16;
89 m_refresh_hwdebug_info =
true;
96uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount()
const {
100uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount()
const {
102 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
103 count += GetRegisterSet(set_index)->num_registers;
108NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index)
const {
109 return GetRegisterInfo().GetRegisterSet(set_index);
113NativeRegisterContextLinux_arm::ReadRegister(
const RegisterInfo *reg_info,
128 }
else if (IsTLS(reg)) {
134 uint32_t full_reg = reg;
143 error = ReadRegisterRaw(full_reg, reg_value);
145 if (
error.Success()) {
161 uint32_t fpr_offset = CalculateFprOffset(reg_info);
162 assert(fpr_offset <
sizeof m_fpr);
163 uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
175 reg_value.
SetBytes(src, 16, GetByteOrder());
178 assert(
false &&
"Unhandled data size.");
188NativeRegisterContextLinux_arm::WriteRegister(
const RegisterInfo *reg_info,
196 "no lldb regnum for %s",
197 reg_info && reg_info->
name ? reg_info->
name :
"<unknown register>");
199 if (IsGPR(reg_index))
200 return WriteRegisterRaw(reg_index, reg_value);
202 if (IsFPR(reg_index)) {
204 uint32_t fpr_offset = CalculateFprOffset(reg_info);
205 assert(fpr_offset <
sizeof m_fpr);
206 uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
212 if (IsTLS(reg_index))
214 "writing to a thread pointer register is not implemented");
217 "failed - register wasn't recognized to be a GPR or an FPR, "
218 "write strategy unknown");
221Status NativeRegisterContextLinux_arm::ReadAllRegisterValues(
238 uint8_t *dst = data_sp->GetBytes();
239 ::memcpy(dst, &m_gpr_arm, GetGPRSize());
241 ::memcpy(dst, &m_fpr,
sizeof(m_fpr));
242 dst +=
sizeof(m_fpr);
243 ::memcpy(dst, &m_tls,
sizeof(m_tls));
248Status NativeRegisterContextLinux_arm::WriteAllRegisterValues(
254 "NativeRegisterContextLinux_arm::%s invalid data_sp provided",
261 "NativeRegisterContextLinux_arm::%s data_sp contained mismatched "
262 "data size, expected %" PRIu64
", actual %" PRIu64,
267 const uint8_t *src = data_sp->GetBytes();
268 if (src ==
nullptr) {
270 "NativeRegisterContextLinux_arm::%s "
271 "DataBuffer::GetBytes() returned a null "
276 ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
282 src += GetRegisterInfoInterface().GetGPRSize();
283 ::memcpy(&m_fpr, src,
sizeof(m_fpr));
294bool NativeRegisterContextLinux_arm::IsGPR(
unsigned reg)
const {
295 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
301bool NativeRegisterContextLinux_arm::IsFPR(
unsigned reg)
const {
302 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
308bool NativeRegisterContextLinux_arm::IsTLS(
unsigned reg)
const {
309 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
313llvm::Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
314 if (!m_refresh_hwdebug_info)
315 return llvm::Error::success();
318 unsigned int cap_val;
320 PTRACE_GETHBPREGS, m_thread.GetID(),
nullptr, &cap_val,
321 sizeof(
unsigned int));
324 return error.ToError();
326 m_max_hwp_supported = (cap_val >> 8) & 0xff;
327 m_max_hbp_supported = cap_val & 0xff;
328 m_refresh_hwdebug_info =
false;
330 return error.ToError();
339NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(DREGType hwbType) {
341 uint32_t max_index = m_max_hbp_supported;
342 if (hwbType == eDREGTypeWATCH)
343 max_index = m_max_hwp_supported;
345 for (uint32_t idx = 0; idx < max_index; ++idx)
346 if (
auto error = WriteHardwareDebugReg(hwbType, idx))
349 return llvm::Error::success();
351 uint32_t max_supported =
353 ? m_max_hwp_supported
354 : m_max_hbp_supported;
366NativeRegisterContextLinux_arm::WriteHardwareDebugReg(DREGType hwbType,
371 int addr_idx = (hwb_index << 1) + 1;
372 int ctrl_idx = addr_idx + 1;
376 addr_buf = &m_hwp_regs[hwb_index].address;
378 ctrl_buf = &m_hwp_regs[hwb_index].control;
380 addr_buf = &m_hbp_regs[hwb_index].address;
381 ctrl_buf = &m_hbp_regs[hwb_index].control;
385 PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)addr_idx,
386 addr_buf,
sizeof(
unsigned int));
389 return error.ToError();
392 PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)ctrl_idx,
393 ctrl_buf,
sizeof(
unsigned int));
395 return error.ToError();
399uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
404Status NativeRegisterContextLinux_arm::DoReadRegisterValue(
405 uint32_t offset,
const char *reg_name, uint32_t size,
412 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
413 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
415 "Register isn't fit into the size of the GPR area");
421 value.
SetUInt32(m_gpr_arm[offset /
sizeof(uint32_t)]);
425Status NativeRegisterContextLinux_arm::DoWriteRegisterValue(
426 uint32_t offset,
const char *reg_name,
const RegisterValue &value) {
432 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
433 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
435 "Register isn't fit into the size of the GPR area");
445 if (offset /
sizeof(uint32_t) ==
gpr_pc_arm) {
450 reg_value &= (~1ull);
454 m_gpr_arm[offset /
sizeof(uint32_t)] = reg_value;
458Status NativeRegisterContextLinux_arm::ReadGPR() {
463 ioVec.iov_base = GetGPRBuffer();
464 ioVec.iov_len = GetGPRSize();
466 return ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
470Status NativeRegisterContextLinux_arm::WriteGPR() {
475 ioVec.iov_base = GetGPRBuffer();
476 ioVec.iov_len = GetGPRSize();
478 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
482Status NativeRegisterContextLinux_arm::ReadFPR() {
485 nullptr, GetFPRBuffer(),
489 ioVec.iov_base = GetFPRBuffer();
490 ioVec.iov_len = GetFPRSize();
492 return ReadRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
496Status NativeRegisterContextLinux_arm::WriteFPR() {
499 nullptr, GetFPRBuffer(),
503 ioVec.iov_base = GetFPRBuffer();
504 ioVec.iov_len = GetFPRSize();
506 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
510Status NativeRegisterContextLinux_arm::ReadTLS() {
513 m_thread.GetID(),
nullptr,
514 GetTLSBuffer(), GetTLSSize());
519 ioVec.iov_base = GetTLSBuffer();
520 ioVec.iov_len = GetTLSSize();
522 return ReadRegisterSet(&ioVec, GetTLSSize(), NT_ARM_TLS);
static llvm::raw_ostream & error(Stream &strm)
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.