9#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
26#if defined(__arm64__) || defined(__aarch64__)
29#include <asm/ptrace.h>
32#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr))
34#ifndef PTRACE_GETVFPREGS
35#define PTRACE_GETVFPREGS 27
36#define PTRACE_SETVFPREGS 28
38#if defined(__arm__) && !defined(PTRACE_GETHBPREGS)
39#define PTRACE_GETHBPREGS 29
40#define PTRACE_SETHBPREGS 30
42#if !defined(PTRACE_TYPE_ARG3)
43#define PTRACE_TYPE_ARG3 void *
45#if !defined(PTRACE_TYPE_ARG4)
46#define PTRACE_TYPE_ARG4 void *
55std::unique_ptr<NativeRegisterContextLinux>
58 return std::make_unique<NativeRegisterContextLinux_arm>(target_arch,
62llvm::Expected<ArchSpec>
64 return HostInfo::GetArchitecture();
69NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
74 assert(target_arch.GetMachine() == llvm::Triple::arm);
76 ::memset(&m_fpr, 0,
sizeof(m_fpr));
77 ::memset(&m_gpr_arm, 0,
sizeof(m_gpr_arm));
78 ::memset(&m_hwp_regs, 0,
sizeof(m_hwp_regs));
79 ::memset(&m_hbp_regs, 0,
sizeof(m_hbp_regs));
82 m_max_hwp_supported = 16;
83 m_max_hbp_supported = 16;
84 m_refresh_hwdebug_info =
true;
91uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount()
const {
95uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount()
const {
97 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
98 count += GetRegisterSet(set_index)->num_registers;
103NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index)
const {
104 return GetRegisterInfo().GetRegisterSet(set_index);
108NativeRegisterContextLinux_arm::ReadRegister(
const RegisterInfo *reg_info,
124 uint32_t full_reg = reg;
133 error = ReadRegisterRaw(full_reg, reg_value);
135 if (
error.Success()) {
151 uint32_t fpr_offset = CalculateFprOffset(reg_info);
152 assert(fpr_offset <
sizeof m_fpr);
153 uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
165 reg_value.
SetBytes(src, 16, GetByteOrder());
168 assert(
false &&
"Unhandled data size.");
178NativeRegisterContextLinux_arm::WriteRegister(
const RegisterInfo *reg_info,
186 "no lldb regnum for %s",
187 reg_info && reg_info->
name ? reg_info->
name :
"<unknown register>");
189 if (IsGPR(reg_index))
190 return WriteRegisterRaw(reg_index, reg_value);
192 if (IsFPR(reg_index)) {
194 uint32_t fpr_offset = CalculateFprOffset(reg_info);
195 assert(fpr_offset <
sizeof m_fpr);
196 uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
203 "failed - register wasn't recognized to be a GPR or an FPR, "
204 "write strategy unknown");
207Status NativeRegisterContextLinux_arm::ReadAllRegisterValues(
220 uint8_t *dst = data_sp->GetBytes();
221 ::memcpy(dst, &m_gpr_arm, GetGPRSize());
223 ::memcpy(dst, &m_fpr,
sizeof(m_fpr));
228Status NativeRegisterContextLinux_arm::WriteAllRegisterValues(
234 "NativeRegisterContextLinux_arm::%s invalid data_sp provided",
241 "NativeRegisterContextLinux_arm::%s data_sp contained mismatched "
242 "data size, expected %" PRIu64
", actual %" PRIu64,
247 const uint8_t *src = data_sp->GetBytes();
248 if (src ==
nullptr) {
250 "NativeRegisterContextLinux_arm::%s "
251 "DataBuffer::GetBytes() returned a null "
256 ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
262 src += GetRegisterInfoInterface().GetGPRSize();
263 ::memcpy(&m_fpr, src,
sizeof(m_fpr));
272bool NativeRegisterContextLinux_arm::IsGPR(
unsigned reg)
const {
273 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
279bool NativeRegisterContextLinux_arm::IsFPR(
unsigned reg)
const {
280 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
286llvm::Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
287 if (!m_refresh_hwdebug_info)
288 return llvm::Error::success();
291 unsigned int cap_val;
293 PTRACE_GETHBPREGS, m_thread.GetID(),
nullptr, &cap_val,
294 sizeof(
unsigned int));
297 return error.ToError();
299 m_max_hwp_supported = (cap_val >> 8) & 0xff;
300 m_max_hbp_supported = cap_val & 0xff;
301 m_refresh_hwdebug_info =
false;
303 return error.ToError();
312NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(DREGType hwbType) {
314 uint32_t max_index = m_max_hbp_supported;
315 if (hwbType == eDREGTypeWATCH)
316 max_index = m_max_hwp_supported;
318 for (uint32_t idx = 0; idx < max_index; ++idx)
319 if (
auto error = WriteHardwareDebugReg(hwbType, idx))
322 return llvm::Error::success();
324 uint32_t max_supported =
326 ? m_max_hwp_supported
327 : m_max_hbp_supported;
339NativeRegisterContextLinux_arm::WriteHardwareDebugReg(DREGType hwbType,
344 int addr_idx = (hwb_index << 1) + 1;
345 int ctrl_idx = addr_idx + 1;
349 addr_buf = &m_hwp_regs[hwb_index].address;
351 ctrl_buf = &m_hwp_regs[hwb_index].control;
353 addr_buf = &m_hbp_regs[hwb_index].address;
354 ctrl_buf = &m_hbp_regs[hwb_index].control;
358 PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)addr_idx,
359 addr_buf,
sizeof(
unsigned int));
362 return error.ToError();
365 PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)ctrl_idx,
366 ctrl_buf,
sizeof(
unsigned int));
368 return error.ToError();
372uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
377Status NativeRegisterContextLinux_arm::DoReadRegisterValue(
378 uint32_t offset,
const char *reg_name, uint32_t size,
385 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
386 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
388 "Register isn't fit into the size of the GPR area");
394 value.
SetUInt32(m_gpr_arm[offset /
sizeof(uint32_t)]);
398Status NativeRegisterContextLinux_arm::DoWriteRegisterValue(
399 uint32_t offset,
const char *reg_name,
const RegisterValue &value) {
405 assert(offset % 4 == 0 &&
"Try to write a register with unaligned offset");
406 if (offset +
sizeof(uint32_t) >
sizeof(m_gpr_arm))
408 "Register isn't fit into the size of the GPR area");
418 if (offset /
sizeof(uint32_t) ==
gpr_pc_arm) {
423 reg_value &= (~1ull);
427 m_gpr_arm[offset /
sizeof(uint32_t)] = reg_value;
431Status NativeRegisterContextLinux_arm::ReadGPR() {
436 ioVec.iov_base = GetGPRBuffer();
437 ioVec.iov_len = GetGPRSize();
439 return ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
443Status NativeRegisterContextLinux_arm::WriteGPR() {
448 ioVec.iov_base = GetGPRBuffer();
449 ioVec.iov_len = GetGPRSize();
451 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
455Status NativeRegisterContextLinux_arm::ReadFPR() {
458 nullptr, GetFPRBuffer(),
462 ioVec.iov_base = GetFPRBuffer();
463 ioVec.iov_len = GetFPRSize();
465 return ReadRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
469Status NativeRegisterContextLinux_arm::WriteFPR() {
472 nullptr, GetFPRBuffer(),
476 ioVec.iov_base = GetFPRBuffer();
477 ioVec.iov_len = GetFPRSize();
479 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
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.