9#if defined(__loongarch__) && __loongarch_grlen == 64
31#ifndef NT_LOONGARCH_LSX
32#define NT_LOONGARCH_LSX 0xa02
36#ifndef NT_LOONGARCH_LASX
37#define NT_LOONGARCH_LASX 0xa03
41#ifndef NT_LOONGARCH_HW_BREAK
42#define NT_LOONGARCH_HW_BREAK 0xa05
46#ifndef NT_LOONGARCH_HW_WATCH
47#define NT_LOONGARCH_HW_WATCH 0xa06
50#define REG_CONTEXT_SIZE \
51 (GetGPRSize() + GetFPRSize() + sizeof(m_lsx) + sizeof(m_lasx))
60struct loongarch_user_watch_state {
74std::unique_ptr<NativeRegisterContextLinux>
77 switch (target_arch.GetMachine()) {
78 case llvm::Triple::loongarch64: {
80 auto register_info_up = std::make_unique<RegisterInfoPOSIX_loongarch64>(
81 target_arch, opt_regsets);
82 return std::make_unique<NativeRegisterContextLinux_loongarch64>(
83 target_arch, native_thread, std::move(register_info_up));
86 llvm_unreachable(
"have no register context for architecture");
90llvm::Expected<ArchSpec>
92 return HostInfo::GetArchitecture();
95NativeRegisterContextLinux_loongarch64::NativeRegisterContextLinux_loongarch64(
97 std::unique_ptr<RegisterInfoPOSIX_loongarch64> register_info_up)
99 register_info_up.release()),
101 ::memset(&m_fpr, 0,
sizeof(m_fpr));
102 ::memset(&m_gpr, 0,
sizeof(m_gpr));
103 ::memset(&m_lsx, 0,
sizeof(m_lsx));
104 ::memset(&m_lasx, 0,
sizeof(m_lasx));
109 m_max_hwp_supported = 14;
110 m_max_hbp_supported = 14;
111 m_refresh_hwdebug_info =
true;
113 m_gpr_is_valid =
false;
114 m_fpu_is_valid =
false;
115 m_lsx_is_valid =
false;
116 m_lasx_is_valid =
false;
120NativeRegisterContextLinux_loongarch64::GetRegisterInfo()
const {
125uint32_t NativeRegisterContextLinux_loongarch64::GetRegisterSetCount()
const {
129const RegisterSet *NativeRegisterContextLinux_loongarch64::GetRegisterSet(
130 uint32_t set_index)
const {
131 return GetRegisterInfo().GetRegisterSet(set_index);
134uint32_t NativeRegisterContextLinux_loongarch64::GetUserRegisterCount()
const {
136 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
141Status NativeRegisterContextLinux_loongarch64::ReadRegister(
154 "no lldb regnum for %s",
155 reg_info && reg_info->
name ? reg_info->
name :
"<unknown register>");
157 uint8_t *src =
nullptr;
166 assert(offset < GetGPRSize());
167 src = (uint8_t *)GetGPRBuffer() + offset;
169 }
else if (IsFPR(reg)) {
174 offset = CalculateFprOffset(reg_info);
175 assert(offset < GetFPRSize());
176 src = (uint8_t *)GetFPRBuffer() + offset;
177 }
else if (IsLSX(reg)) {
182 offset = CalculateLsxOffset(reg_info);
183 assert(offset <
sizeof(m_lsx));
184 src = (uint8_t *)&m_lsx + offset;
185 }
else if (IsLASX(reg)) {
190 offset = CalculateLasxOffset(reg_info);
191 assert(offset <
sizeof(m_lasx));
192 src = (uint8_t *)&m_lasx + offset;
195 "failed - register wasn't recognized to be a GPR or an FPR, "
196 "write strategy unknown");
204Status NativeRegisterContextLinux_loongarch64::WriteRegister(
215 "no lldb regnum for %s",
216 reg_info->
name !=
nullptr ? reg_info->
name :
"<unknown register>");
218 uint8_t *dst =
nullptr;
227 dst = (uint8_t *)GetGPRBuffer() + reg_info->
byte_offset;
231 }
else if (IsFPR(reg)) {
236 offset = CalculateFprOffset(reg_info);
237 assert(offset < GetFPRSize());
238 dst = (uint8_t *)GetFPRBuffer() + offset;
242 }
else if (IsLSX(reg)) {
247 offset = CalculateLsxOffset(reg_info);
248 assert(offset <
sizeof(m_lsx));
249 dst = (uint8_t *)&m_lsx + offset;
253 }
else if (IsLASX(reg)) {
258 offset = CalculateLasxOffset(reg_info);
259 assert(offset <
sizeof(m_lasx));
260 dst = (uint8_t *)&m_lasx + offset;
269Status NativeRegisterContextLinux_loongarch64::ReadAllRegisterValues(
291 uint8_t *dst = data_sp->GetBytes();
292 ::memcpy(dst, GetGPRBuffer(), GetGPRSize());
294 ::memcpy(dst, GetFPRBuffer(), GetFPRSize());
296 ::memcpy(dst, &m_lsx,
sizeof(m_lsx));
297 dst +=
sizeof(m_lsx);
298 ::memcpy(dst, &m_lasx,
sizeof(m_lasx));
303Status NativeRegisterContextLinux_loongarch64::WriteAllRegisterValues(
309 "NativeRegisterContextLinux_loongarch64::%s invalid data_sp provided",
316 "NativeRegisterContextLinux_loongarch64::%s data_sp contained "
317 "mismatched data size, expected %" PRIu64
", actual %" PRIu64,
322 const uint8_t *src = data_sp->GetBytes();
323 if (src ==
nullptr) {
325 "NativeRegisterContextLinux_loongarch64::%s "
326 "DataBuffer::GetBytes() returned a null "
331 ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize());
337 src += GetRegisterInfoInterface().GetGPRSize();
338 ::memcpy(GetFPRBuffer(), src, GetFPRSize());
339 m_fpu_is_valid =
true;
347 ::memcpy(&m_lsx, src,
sizeof(m_lsx));
348 m_lsx_is_valid =
true;
353 src +=
sizeof(m_lsx);
354 ::memcpy(&m_lasx, src,
sizeof(m_lasx));
355 m_lasx_is_valid =
true;
363bool NativeRegisterContextLinux_loongarch64::IsGPR(
unsigned reg)
const {
364 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
368bool NativeRegisterContextLinux_loongarch64::IsFPR(
unsigned reg)
const {
369 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
373bool NativeRegisterContextLinux_loongarch64::IsLSX(
unsigned reg)
const {
374 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
378bool NativeRegisterContextLinux_loongarch64::IsLASX(
unsigned reg)
const {
379 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
383Status NativeRegisterContextLinux_loongarch64::ReadGPR() {
390 ioVec.iov_base = GetGPRBuffer();
391 ioVec.iov_len = GetGPRSize();
393 error = ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
396 m_gpr_is_valid =
true;
401Status NativeRegisterContextLinux_loongarch64::WriteGPR() {
407 ioVec.iov_base = GetGPRBuffer();
408 ioVec.iov_len = GetGPRSize();
410 m_gpr_is_valid =
false;
412 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
415Status NativeRegisterContextLinux_loongarch64::ReadFPR() {
422 ioVec.iov_base = GetFPRBuffer();
423 ioVec.iov_len = GetFPRSize();
425 error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
428 m_fpu_is_valid =
true;
433Status NativeRegisterContextLinux_loongarch64::WriteFPR() {
439 ioVec.iov_base = GetFPRBuffer();
440 ioVec.iov_len = GetFPRSize();
442 m_fpu_is_valid =
false;
443 m_lsx_is_valid =
false;
444 m_lasx_is_valid =
false;
446 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
449Status NativeRegisterContextLinux_loongarch64::ReadLSX() {
456 ioVec.iov_base = &m_lsx;
457 ioVec.iov_len =
sizeof(m_lsx);
459 error = ReadRegisterSet(&ioVec,
sizeof(m_lsx), NT_LOONGARCH_LSX);
462 m_lsx_is_valid =
true;
467Status NativeRegisterContextLinux_loongarch64::WriteLSX() {
473 ioVec.iov_base = &m_lsx;
474 ioVec.iov_len =
sizeof(m_lsx);
476 m_fpu_is_valid =
false;
477 m_lsx_is_valid =
false;
478 m_lasx_is_valid =
false;
480 return WriteRegisterSet(&ioVec,
sizeof(m_lsx), NT_LOONGARCH_LSX);
483Status NativeRegisterContextLinux_loongarch64::ReadLASX() {
490 ioVec.iov_base = &m_lasx;
491 ioVec.iov_len =
sizeof(m_lasx);
493 error = ReadRegisterSet(&ioVec,
sizeof(m_lasx), NT_LOONGARCH_LASX);
496 m_lasx_is_valid =
true;
501Status NativeRegisterContextLinux_loongarch64::WriteLASX() {
507 ioVec.iov_base = &m_lasx;
508 ioVec.iov_len =
sizeof(m_lasx);
510 m_fpu_is_valid =
false;
511 m_lsx_is_valid =
false;
512 m_lasx_is_valid =
false;
514 return WriteRegisterSet(&ioVec,
sizeof(m_lasx), NT_LOONGARCH_LASX);
517void NativeRegisterContextLinux_loongarch64::InvalidateAllRegisters() {
518 m_gpr_is_valid =
false;
519 m_fpu_is_valid =
false;
520 m_lsx_is_valid =
false;
521 m_lasx_is_valid =
false;
524uint32_t NativeRegisterContextLinux_loongarch64::CalculateFprOffset(
529uint32_t NativeRegisterContextLinux_loongarch64::CalculateLsxOffset(
531 return reg_info->
byte_offset - GetGPRSize() -
sizeof(m_fpr);
534uint32_t NativeRegisterContextLinux_loongarch64::CalculateLasxOffset(
536 return reg_info->
byte_offset - GetGPRSize() -
sizeof(m_fpr) -
sizeof(m_lsx);
540NativeRegisterContextLinux_loongarch64::GetExpeditedRegisters(
542 std::vector<uint32_t> expedited_reg_nums =
545 return expedited_reg_nums;
548llvm::Error NativeRegisterContextLinux_loongarch64::ReadHardwareDebugInfo() {
549 if (!m_refresh_hwdebug_info)
550 return llvm::Error::success();
552 ::pid_t tid = m_thread.GetID();
554 int regset = NT_LOONGARCH_HW_WATCH;
556 struct loongarch_user_watch_state dreg_state;
559 ioVec.iov_base = &dreg_state;
560 ioVec.iov_len =
sizeof(dreg_state);
562 &ioVec, ioVec.iov_len);
564 return error.ToError();
566 m_max_hwp_supported = dreg_state.dbg_info & 0x3f;
568 regset = NT_LOONGARCH_HW_BREAK;
570 &ioVec, ioVec.iov_len);
572 return error.ToError();
574 m_max_hbp_supported = dreg_state.dbg_info & 0x3f;
576 m_refresh_hwdebug_info =
false;
578 return llvm::Error::success();
581llvm::Error NativeRegisterContextLinux_loongarch64::WriteHardwareDebugRegs(
584 struct loongarch_user_watch_state dreg_state;
587 memset(&dreg_state, 0,
sizeof(dreg_state));
588 ioVec.iov_base = &dreg_state;
592 regset = NT_LOONGARCH_HW_WATCH;
593 ioVec.iov_len =
sizeof(dreg_state.dbg_info) +
594 (
sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
596 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
597 dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
598 dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
602 regset = NT_LOONGARCH_HW_BREAK;
603 ioVec.iov_len =
sizeof(dreg_state.dbg_info) +
604 (
sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
606 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
607 dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address;
608 dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control;
614 ®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.