9#if defined(__loongarch__) && __loongarch_grlen == 64
26#include <sys/ptrace.h>
29#ifndef PTRACE_GETREGSET
30#define PTRACE_GETREGSET 0x4204
33#ifndef PTRACE_SETREGSET
34#define PTRACE_SETREGSET 0x4205
38#ifndef NT_LOONGARCH_LSX
39#define NT_LOONGARCH_LSX 0xa02
43#ifndef NT_LOONGARCH_LASX
44#define NT_LOONGARCH_LASX 0xa03
48#ifndef NT_LOONGARCH_HW_BREAK
49#define NT_LOONGARCH_HW_BREAK 0xa05
53#ifndef NT_LOONGARCH_HW_WATCH
54#define NT_LOONGARCH_HW_WATCH 0xa06
57#define REG_CONTEXT_SIZE \
58 (GetGPRSize() + GetFPRSize() + sizeof(m_lsx) + sizeof(m_lasx))
67struct loongarch_user_watch_state {
81std::unique_ptr<NativeRegisterContextLinux>
84 switch (target_arch.GetMachine()) {
85 case llvm::Triple::loongarch64: {
87 auto register_info_up = std::make_unique<RegisterInfoPOSIX_loongarch64>(
88 target_arch, opt_regsets);
89 return std::make_unique<NativeRegisterContextLinux_loongarch64>(
90 target_arch, native_thread, std::move(register_info_up));
93 llvm_unreachable(
"have no register context for architecture");
97llvm::Expected<ArchSpec>
99 return HostInfo::GetArchitecture();
102NativeRegisterContextLinux_loongarch64::NativeRegisterContextLinux_loongarch64(
104 std::unique_ptr<RegisterInfoPOSIX_loongarch64> register_info_up)
106 register_info_up.release()),
108 ::memset(&m_fpr, 0,
sizeof(m_fpr));
109 ::memset(&m_gpr, 0,
sizeof(m_gpr));
110 ::memset(&m_lsx, 0,
sizeof(m_lsx));
111 ::memset(&m_lasx, 0,
sizeof(m_lasx));
116 m_max_hwp_supported = 14;
117 m_max_hbp_supported = 14;
118 m_refresh_hwdebug_info =
true;
120 m_gpr_is_valid =
false;
121 m_fpu_is_valid =
false;
122 m_lsx_is_valid =
false;
123 m_lasx_is_valid =
false;
127NativeRegisterContextLinux_loongarch64::GetRegisterInfo()
const {
132uint32_t NativeRegisterContextLinux_loongarch64::GetRegisterSetCount()
const {
136const RegisterSet *NativeRegisterContextLinux_loongarch64::GetRegisterSet(
137 uint32_t set_index)
const {
138 return GetRegisterInfo().GetRegisterSet(set_index);
141uint32_t NativeRegisterContextLinux_loongarch64::GetUserRegisterCount()
const {
143 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
148Status NativeRegisterContextLinux_loongarch64::ReadRegister(
161 "no lldb regnum for %s",
162 reg_info && reg_info->
name ? reg_info->
name :
"<unknown register>");
164 uint8_t *src =
nullptr;
173 assert(offset < GetGPRSize());
174 src = (uint8_t *)GetGPRBuffer() + offset;
176 }
else if (IsFPR(reg)) {
181 offset = CalculateFprOffset(reg_info);
182 assert(offset < GetFPRSize());
183 src = (uint8_t *)GetFPRBuffer() + offset;
184 }
else if (IsLSX(reg)) {
189 offset = CalculateLsxOffset(reg_info);
190 assert(offset <
sizeof(m_lsx));
191 src = (uint8_t *)&m_lsx + offset;
192 }
else if (IsLASX(reg)) {
197 offset = CalculateLasxOffset(reg_info);
198 assert(offset <
sizeof(m_lasx));
199 src = (uint8_t *)&m_lasx + offset;
202 "failed - register wasn't recognized to be a GPR or an FPR, "
203 "write strategy unknown");
211Status NativeRegisterContextLinux_loongarch64::WriteRegister(
222 "no lldb regnum for %s",
223 reg_info->
name !=
nullptr ? reg_info->
name :
"<unknown register>");
225 uint8_t *dst =
nullptr;
234 dst = (uint8_t *)GetGPRBuffer() + reg_info->
byte_offset;
238 }
else if (IsFPR(reg)) {
243 offset = CalculateFprOffset(reg_info);
244 assert(offset < GetFPRSize());
245 dst = (uint8_t *)GetFPRBuffer() + offset;
249 }
else if (IsLSX(reg)) {
254 offset = CalculateLsxOffset(reg_info);
255 assert(offset <
sizeof(m_lsx));
256 dst = (uint8_t *)&m_lsx + offset;
260 }
else if (IsLASX(reg)) {
265 offset = CalculateLasxOffset(reg_info);
266 assert(offset <
sizeof(m_lasx));
267 dst = (uint8_t *)&m_lasx + offset;
276Status NativeRegisterContextLinux_loongarch64::ReadAllRegisterValues(
298 uint8_t *dst = data_sp->GetBytes();
299 ::memcpy(dst, GetGPRBuffer(), GetGPRSize());
301 ::memcpy(dst, GetFPRBuffer(), GetFPRSize());
303 ::memcpy(dst, &m_lsx,
sizeof(m_lsx));
304 dst +=
sizeof(m_lsx);
305 ::memcpy(dst, &m_lasx,
sizeof(m_lasx));
310Status NativeRegisterContextLinux_loongarch64::WriteAllRegisterValues(
316 "NativeRegisterContextLinux_loongarch64::%s invalid data_sp provided",
323 "NativeRegisterContextLinux_loongarch64::%s data_sp contained "
324 "mismatched data size, expected %" PRIu64
", actual %" PRIu64,
329 const uint8_t *src = data_sp->GetBytes();
330 if (src ==
nullptr) {
332 "NativeRegisterContextLinux_loongarch64::%s "
333 "DataBuffer::GetBytes() returned a null "
338 ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize());
344 src += GetRegisterInfoInterface().GetGPRSize();
345 ::memcpy(GetFPRBuffer(), src, GetFPRSize());
346 m_fpu_is_valid =
true;
354 ::memcpy(&m_lsx, src,
sizeof(m_lsx));
355 m_lsx_is_valid =
true;
360 src +=
sizeof(m_lsx);
361 ::memcpy(&m_lasx, src,
sizeof(m_lasx));
362 m_lasx_is_valid =
true;
370bool NativeRegisterContextLinux_loongarch64::IsGPR(
unsigned reg)
const {
371 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
375bool NativeRegisterContextLinux_loongarch64::IsFPR(
unsigned reg)
const {
376 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
380bool NativeRegisterContextLinux_loongarch64::IsLSX(
unsigned reg)
const {
381 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
385bool NativeRegisterContextLinux_loongarch64::IsLASX(
unsigned reg)
const {
386 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
390Status NativeRegisterContextLinux_loongarch64::ReadGPR() {
397 ioVec.iov_base = GetGPRBuffer();
398 ioVec.iov_len = GetGPRSize();
400 error = ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
403 m_gpr_is_valid =
true;
408Status NativeRegisterContextLinux_loongarch64::WriteGPR() {
414 ioVec.iov_base = GetGPRBuffer();
415 ioVec.iov_len = GetGPRSize();
417 m_gpr_is_valid =
false;
419 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
422Status NativeRegisterContextLinux_loongarch64::ReadFPR() {
429 ioVec.iov_base = GetFPRBuffer();
430 ioVec.iov_len = GetFPRSize();
432 error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
435 m_fpu_is_valid =
true;
440Status NativeRegisterContextLinux_loongarch64::WriteFPR() {
446 ioVec.iov_base = GetFPRBuffer();
447 ioVec.iov_len = GetFPRSize();
449 m_fpu_is_valid =
false;
450 m_lsx_is_valid =
false;
451 m_lasx_is_valid =
false;
453 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
456Status NativeRegisterContextLinux_loongarch64::ReadLSX() {
463 ioVec.iov_base = &m_lsx;
464 ioVec.iov_len =
sizeof(m_lsx);
466 error = ReadRegisterSet(&ioVec,
sizeof(m_lsx), NT_LOONGARCH_LSX);
469 m_lsx_is_valid =
true;
474Status NativeRegisterContextLinux_loongarch64::WriteLSX() {
480 ioVec.iov_base = &m_lsx;
481 ioVec.iov_len =
sizeof(m_lsx);
483 m_fpu_is_valid =
false;
484 m_lsx_is_valid =
false;
485 m_lasx_is_valid =
false;
487 return WriteRegisterSet(&ioVec,
sizeof(m_lsx), NT_LOONGARCH_LSX);
490Status NativeRegisterContextLinux_loongarch64::ReadLASX() {
497 ioVec.iov_base = &m_lasx;
498 ioVec.iov_len =
sizeof(m_lasx);
500 error = ReadRegisterSet(&ioVec,
sizeof(m_lasx), NT_LOONGARCH_LASX);
503 m_lasx_is_valid =
true;
508Status NativeRegisterContextLinux_loongarch64::WriteLASX() {
514 ioVec.iov_base = &m_lasx;
515 ioVec.iov_len =
sizeof(m_lasx);
517 m_fpu_is_valid =
false;
518 m_lsx_is_valid =
false;
519 m_lasx_is_valid =
false;
521 return WriteRegisterSet(&ioVec,
sizeof(m_lasx), NT_LOONGARCH_LASX);
524void NativeRegisterContextLinux_loongarch64::InvalidateAllRegisters() {
525 m_gpr_is_valid =
false;
526 m_fpu_is_valid =
false;
527 m_lsx_is_valid =
false;
528 m_lasx_is_valid =
false;
531uint32_t NativeRegisterContextLinux_loongarch64::CalculateFprOffset(
536uint32_t NativeRegisterContextLinux_loongarch64::CalculateLsxOffset(
538 return reg_info->
byte_offset - GetGPRSize() -
sizeof(m_fpr);
541uint32_t NativeRegisterContextLinux_loongarch64::CalculateLasxOffset(
543 return reg_info->
byte_offset - GetGPRSize() -
sizeof(m_fpr) -
sizeof(m_lsx);
547NativeRegisterContextLinux_loongarch64::GetExpeditedRegisters(
549 std::vector<uint32_t> expedited_reg_nums =
552 return expedited_reg_nums;
555llvm::Error NativeRegisterContextLinux_loongarch64::ReadHardwareDebugInfo() {
556 if (!m_refresh_hwdebug_info)
557 return llvm::Error::success();
559 ::pid_t tid = m_thread.GetID();
561 int regset = NT_LOONGARCH_HW_WATCH;
563 struct loongarch_user_watch_state dreg_state;
566 ioVec.iov_base = &dreg_state;
567 ioVec.iov_len =
sizeof(dreg_state);
569 &ioVec, ioVec.iov_len);
571 return error.ToError();
573 m_max_hwp_supported = dreg_state.dbg_info & 0x3f;
575 regset = NT_LOONGARCH_HW_BREAK;
577 &ioVec, ioVec.iov_len);
579 return error.ToError();
581 m_max_hbp_supported = dreg_state.dbg_info & 0x3f;
583 m_refresh_hwdebug_info =
false;
585 return llvm::Error::success();
588llvm::Error NativeRegisterContextLinux_loongarch64::WriteHardwareDebugRegs(
591 struct loongarch_user_watch_state dreg_state;
594 memset(&dreg_state, 0,
sizeof(dreg_state));
595 ioVec.iov_base = &dreg_state;
599 regset = NT_LOONGARCH_HW_WATCH;
600 ioVec.iov_len =
sizeof(dreg_state.dbg_info) +
601 (
sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
603 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
604 dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
605 dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
609 regset = NT_LOONGARCH_HW_BREAK;
610 ioVec.iov_len =
sizeof(dreg_state.dbg_info) +
611 (
sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
613 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
614 dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address;
615 dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control;
621 ®set, &ioVec, ioVec.iov_len)
static llvm::raw_ostream & error(Stream &strm)
size_t GetRegisterSetCount() const override
A subclass of DataBuffer that stores a data buffer on the heap.
const RegisterInfoInterface & GetRegisterInfoInterface() const
virtual std::vector< uint32_t > GetExpeditedRegisters(ExpeditedRegs expType) const
uint32_t SetFromMemoryData(const RegisterInfo ®_info, const void *src, uint32_t src_len, lldb::ByteOrder src_byte_order, Status &error)
const void * GetBytes() 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)
static llvm::Expected< ArchSpec > DetermineArchitecture(lldb::tid_t tid)
#define LLDB_INVALID_INDEX32
#define LLDB_INVALID_REGNUM
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.
Registers are grouped into register sets.
size_t num_registers
The number of registers in REGISTERS array below.